Submission #5970

#TimeUsernameProblemLanguageResultExecution timeMemory
5970model_code경계 (BOI14_demarcation)C++98
100 / 100
126 ms11384 KiB
#include <cstdio>
#include <set>
#include <algorithm>
#include <cassert>
using namespace std;

typedef long long ll;
typedef pair <int, int> ii;

const int Maxn = 100005;    // Max number of points
const int Maxe = 2 * Maxn;  // Max number of events
const int Maxr = 4;         // Max number of rotations

// Element in the set ("Line Sweep")
struct element {
	int y, ind, delt;
	element(int y = 0, int ind = 0, int delt = 0): y(y), ind(ind), delt(delt) {}
	bool operator <(const element &e) const {
		return y < e.y;
	}
};

// Event in "Line Sweep"
struct event {
	int x;
	element el;
	bool en;
	event(int x = 0, element el = element(), bool en = false): x(x), el(el), en(en) { }
	bool operator <(const event &e) const {
		if (x != e.x) return x < e.x;
		if (en != e.en) return en < e.en;
		return el.y < e.el.y;
	}
};

// "Candidate" split line
struct line {
	int x, y1, y2;
	line(int x = 0, int y1 = 0, int y2 = 0): x(x), y1(y1), y2(y2) {}
	bool operator <(const line &l) const {
		if (x != l.x) return x < l.x;
		if (y1 != l.y1) return y1 < l.y1;
		return y2 < l.y2;
	}
};

int n;               // Number of points
ii p[Maxn];          // Points of polygon
ll num[Maxn];        // Enumerated points by perimeter
event E[Maxe];       // Events in "Line Sweep"
int elen;
set <line> Spl;      // Can become split line
ii a[Maxn], b[Maxn]; // Candidates to compare
int alen, blen;      // Number of points of candidates

void Move(ii p[], int len, int &nil)
{
	nil = 0;
	for (int i = 0; i < len; i++)
		if (p[i] < p[nil]) nil = i;
	ii d = ii(-p[nil].first, -p[nil].second);
	if (d == ii(0, 0)) return;
	for (int i = 0; i < len; i++)
		p[i] = ii(p[i].first + d.first, p[i].second + d.second);
}

void Rotate(ii p[], int len)
{
	for (int i = 0; i < len; i++)
		p[i] = ii(p[i].second, -p[i].first);
}

void Reflect(ii p[], int len)
{
	for (int i = 0; i < len; i++)
		p[i].second = -p[i].second;
	reverse(p, p + len);
}

bool trivialCompare(ii a[], int alen, int anil, ii b[], int blen, int bnil)
{
	for (int i = 0; i < alen; i++) // alen = blen
		if (a[(anil + i) % alen] != b[(bnil + i) % blen])
			return false;
	return true;
}

bool spinAround(ii a[], int alen, int anil, ii b[], int blen)
{
	int bnil;   // The leftmost (the lowest) point
	for (int i = 0; i < Maxr; i++) {
		Rotate(b, blen);
		Move(b, blen, bnil);
		if (trivialCompare(a, alen, anil, b, blen, bnil))
			return true;
	}
	return false;
}

bool complexCompare(ii a[], int alen, ii b[], int blen)
{
	if (alen != blen) return false;
	int anil;   // The leftmost (the lowest) point
	Move(a, alen, anil);
	if (spinAround(a, alen, anil, b, blen)) return true;
	Reflect(b, blen);
	return spinAround(a, alen, anil, b, blen);
}

ll crossProduct(ll ax, ll ay, ll bx, ll by) { return ax * by - ay * bx; }

ll inLine(ii a, ii b, ii c)
{
	return crossProduct(b.first - a.first, b.second - a.second, 
						c.first - a.first, c.second - a.second) == 0;
}

void addPoint(ii p[], int &len, ii toadd)
{
	if (len == 0) p[len++] = toadd;
	else if (toadd != p[len - 1]) {
			if (len >= 2 && inLine(p[len - 2], p[len - 1], toadd))
				len--;
			p[len++] = toadd;
		}

}

void Construct(ii p[], int len, ii a[], int &alen, int s1, int s2, int x, int y1, int y2)
{
	alen = 0;
	addPoint(a, alen, ii(x, y1));
	int pnt = s1;
	do {
		pnt = (pnt + 1) % len;
		addPoint(a, alen, p[pnt]);
	} while (pnt != s2);
	addPoint(a, alen, ii(x, y2));
	if (alen >= 3 && inLine(a[alen - 2], a[alen - 1], a[0]))
		alen--;
	if (alen >= 3 && inLine(a[alen - 1], a[0], a[1])) {
		alen--;
		for (int i = 0; i < alen; i++)
			a[i] = a[i + 1];
	}
}

void Split(ii p[], int len, int x, int y1, int y2, ii a[], int &alen, ii b[], int &blen)
{
	int s1 = 0;
	while (!(p[s1].second == y1 && p[(s1 + 1) % len].second == y1 && 
		   p[(s1 + 1) % len].first <= x && x <= p[s1].first))
		s1 = (s1 + 1) % len;
	int s2 = 0;
	while (!(p[s2].second == y2 && p[(s2 + 1) % len].second == y2 && 
		   p[s2].first <= x && x <= p[(s2 + 1) % len].first))
		s2 = (s2 + 1) % len;
	Construct(p, len, a, alen, s1, s2, x, y1, y2); 
	Construct(p, len, b, blen, s2, s1, x, y2, y1);
}

void insertEvents(ii p[], int y, int a, int b, int delt)
{
	element el = element(y, a, delt);
	E[elen++] = event(p[a].first, el, false);
	E[elen++] = event(p[b].first, el, true);
}

ll getId(ll num[], const element &el, int curx)
{
	return num[el.ind] + el.delt * (curx - p[el.ind].first);
}

int canGrow(ii p[], int len, const element &el, int curx)
{
	int pi = (el.ind - 1 + len) % len;
	int ni = (el.ind + 1) % len;
	return (el.delt == 1? p[ni].first: p[pi].first) - curx;
}

bool getNear(const element &el, set <element> &S, set <element>::iterator &it)
{
	it = S.find(el);
	if (el.delt == 1)
		if (it == S.begin()) return false;
		else it--;
	else {
		it++;
		if (it == S.end()) return false;
	}
	return el.delt != it->delt;
}

void solveFor(const element &el, set <element> &S, ll num[], ii p[], int len, int curx, set <line> &Spl, bool hardcomp)
{
	set <element>::iterator it;
	if (!getNear(el, S, it)) return; 

	ll id1 = getId(num, el, curx);
	ll id2 = getId(num, *it, curx);
	int cangrow = min(canGrow(p, len, el, curx), canGrow(p, len, *it, curx));
	ll did = el.delt == 1? id1 - id2: id2 - id1;
	if (did < 0) did += num[len];

	ll grow = (num[len] / 2 - did) / 2;
	if ((!hardcomp && grow >= 0 || grow > 0) && grow <= cangrow && 2 * (did + 2 * grow) == num[len])
		Spl.insert(line(curx + grow, min(el.y, it->y), max(el.y, it->y)));
}

bool getVerticalSplit(ii p[], int len, int &x, int &y1, int &y2)
{
	// Prepare perimeter
	num[0] = 0;
	for (int i = 1; i <= len; i++)
		num[i] = num[i - 1] + abs(p[i % len].first - p[i - 1].first) + 
							  abs(p[i % len].second - p[i - 1].second);
	// Prepare events
	elen = 0;
	for (int i = 0; i < len; i++) {
		int ni = (i + 1) % len;
		if (p[i].second == p[ni].second)
			if (p[i].first < p[ni].first)
				insertEvents(p, p[i].second, i, ni, 1);
			else insertEvents(p, p[i].second, ni, i, -1);
	}
	sort(E, E + elen);
	// Line Sweep
	set <element> S;
	for (int i = 0, j; i < elen; i = j) {
		j = i;
		int curx = E[i].x;
		if (!Spl.empty()) curx = min(curx, Spl.begin()->x);

		while (j < elen && curx == E[j].x && !E[j].en) {
			S.insert(E[j].el);
			solveFor(E[j].el, S, num, p, len, curx, Spl, false);
			j++;
		}

		set <line>::iterator it = Spl.begin();
		while (it != Spl.end() && curx == it->x) {
			set <element>::iterator it2 = S.lower_bound(element(it->y1, 0, 0));
			if (it2 == S.end() || it2->y != it->y1) { Spl.erase(it++); continue; }
			it2++;
			if (it2 == S.end() || it2->y != it->y2) { Spl.erase(it++); continue; }
			Split(p, len, it->x, it->y1, it->y2, a, alen, b, blen);
			if (complexCompare(a, alen, b, blen)) {
				x = it->x; y1 = it->y1; y2 = it->y2;
				return true;
			}
			Spl.erase(it++);
		}

		while (j < elen && curx == E[j].x) {
			set <element>::iterator it = S.find(E[j].el);
			S.erase(it++);
			if (it != S.end())
				solveFor(*it, S, num, p, len, curx, Spl, true);
			j++;
		}
	}
	return false;
}

void Init()
{
	scanf("%d", &n);
	int lm = 0; // leftmost
	for (int i = 0; i < n; i++) {
		scanf("%d %d", &p[i].first, &p[i].second);
		if (p[i] < p[lm]) lm = i;
	}
	if (!(p[lm].second < p[(lm + 1) % n].second))
		reverse(p, p + n); // Make clockwise
}

int main()
{
	Init();
	int x, y1, y2;
	if (getVerticalSplit(p, n, x, y1, y2))
		printf("%d %d %d %d\n", x, y1, x, y2);
	else {
		Rotate(p, n);
		if (getVerticalSplit(p, n, x, y1, y2))
			printf("%d %d %d %d\n", -y2, x, -y1, x); // Rotating back
		else printf("NO\n");
	}
	return 0;
}

Compilation message (stderr)

demarcation.cpp: In function 'void solveFor(const element&, std::set<element>&, ll*, ii*, int, int, std::set<line>&, bool)':
demarcation.cpp:206:17: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
  if ((!hardcomp && grow >= 0 || grow > 0) && grow <= cangrow && 2 * (did + 2 * grow) == num[len])
                 ^
demarcation.cpp: In function 'bool getVerticalSplit(ii*, int, int&, int&, int&)':
demarcation.cpp:221:6: warning: suggest explicit braces to avoid ambiguous 'else' [-Wparentheses]
   if (p[i].second == p[ni].second)
      ^
demarcation.cpp: In function 'void Init()':
demarcation.cpp:267:17: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  scanf("%d", &n);
                 ^
demarcation.cpp:270:44: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d %d", &p[i].first, &p[i].second);
                                            ^
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...