#include <map>
#include "testlib.h"
#define MAXN 200005
struct Point
{
int x, y;
Point(){}
Point(int _x, int _y) : x(_x), y(_y) {}
bool operator < (const Point &a) const {
return x == a.x ? y < a.y : x < a.x;
}
Point operator + (const Point &a) const {
return Point(x + a.x, y + a.y);
}
Point operator - (const Point &a) const {
return Point(x - a.x, y - a.y);
}
long long operator * (const Point &a) const {
return 1LL * x * a.y - 1LL * y * a.x;
}
long long operator ^ (const Point &a) const {
return 1LL * x * a.x + 1LL* y * a.y;
}
};
Point p[MAXN], q[MAXN];
int n, m, f[MAXN], l[MAXN], r[MAXN];
std::map <Point, int> mp;
std::vector <std::pair<int, int> > ev;
int X;
struct SegCmp
{
bool operator() (const int i, const int j) const {
Point &A = q[l[i]], &B = q[r[i]];
Point &C = q[l[j]], &D = q[r[j]];
__int128 s = (long long)(B.y - A.y) * (X - A.x) + (long long)A.y * (B.x - A.x);
__int128 t = (long long)(D.y - C.y) * (X - C.x) + (long long)C.y * (D.x - C.x);
__int128 CD = D.x - C.x;
__int128 BA = B.x - A.x;
return s * CD < t * BA;
}
};
std::multiset <int, SegCmp> S;
inline int sgn(long long x) { return x < 0 ? -1 : (x > 0); }
inline bool intersect(const Point &A, const Point &B, const Point &C, const Point &D)
{
int d1 = sgn((B - A) * (C - A)) * sgn((B - A) * (D - A));
int d2 = sgn((D - C) * (A - C)) * sgn((D - C) * (B - C));
return d1 < 0 && d2 < 0;
}
inline bool intersect(int i, int j)
{
//printf("%d %d\n",i,j);
if (i == -1 || j == -1 || i == j) return false;
//printf("%d %d\n",i,j);
//printf("(%d, %d)-(%d, %d)\n",q[l[i]].x,q[l[i]].y,q[r[i]].x,q[r[i]].y);
//printf("(%d, %d)-(%d, %d)\n",q[l[j]].x,q[l[j]].y,q[r[j]].x,q[r[j]].y);
if (!sgn((q[l[i]] - q[r[i]]) * (q[l[j]] - q[r[j]])))
{
if (q[l[i]].x == q[r[i]].x)
{
if (q[l[i]].x != q[l[j]].x) return false;
int iymn = std::min(q[l[i]].y, q[r[i]].y);
int iymx = std::max(q[l[i]].y, q[r[i]].y);
int jymn = std::min(q[l[j]].y, q[r[j]].y);
int jymx = std::max(q[l[j]].y, q[r[j]].y);
if (iymn < jymn)
{
if (iymx <= jymn) return false;
return true;
}
else if (iymn == jymn) return true;
else
{
if (jymn <= iymn) return false;
return true;
}
}
else if (q[l[i]].y == q[r[i]].y)
{
if (q[l[i]].y != q[l[j]].y) return false;
int ixmn = std::min(q[l[i]].x, q[r[i]].x);
int ixmx = std::max(q[l[i]].x, q[r[i]].x);
int jxmn = std::min(q[l[j]].x, q[r[j]].x);
int jxmx = std::max(q[l[j]].x, q[r[j]].x);
if (ixmn < jxmn)
{
if (ixmx <= jxmn) return false;
return true;
}
else if (ixmn == jxmn) return true;
else
{
if (jxmn <= ixmn) return false;
return true;
}
}
}
return intersect(q[l[i]], q[r[i]], q[l[j]], q[r[j]]);
}
int getf(int x){ return x == f[x] ? x : f[x] = getf(f[x]); }
inline void Union(int x, int y)
{
x = getf(x); y = getf(y);
if (x != y) f[y] = x;
return ;
}
bool judge()
{
sort(ev.begin(), ev.end(), [&](const std::pair<int, int> &x, const std::pair<int, int> &y){ return q[x.first] < q[y.first]; });
for (auto P : ev)
{
int x = P.first, t = P.second;
X = q[x].x;
if (t > 0)
{
auto up = S.insert(t), dn = up;
int a = -1, b = -1;
if (up != S.end()) a = *(++up);
if (dn != S.begin()) b = *(--dn);
if (intersect(a, t))
{
//puts("Yes");
return false;
}
if (intersect(b, t))
{
return false;
}
}
else
{
auto up = S.find(-t), dn = up;
int a = -1, b = -1;
if (up != S.end()) a = *(++up);
if (dn != S.begin()) b = *(--dn);
if (intersect(a, b))
{
return false;
}
S.erase(-t);
}
}
return true;
}
bool judgeNoX()
{
ev.clear(); S.clear();
for (int i = 1; i <= m; i++)
q[i] = p[i];
for (int i = 1; i <= n; i++)
{
if (q[r[i]] < q[l[i]]) std::swap(l[i], r[i]);
if (q[l[i]].x != q[r[i]].x)
{
ev.push_back({l[i], i});
ev.push_back({r[i], -i});
}
}
return judge();
}
bool judgeNoY()
{
ev.clear(); S.clear();
for (int i = 1; i <= m; i++)
q[i] = Point(-p[i].y, p[i].x);
for (int i = 1; i <= n; i++)
{
if (q[r[i]] < q[l[i]]) std::swap(l[i], r[i]);
if (q[l[i]].x != q[r[i]].x)
{
ev.push_back({l[i], i});
ev.push_back({r[i], -i});
}
}
return judge();
}
bool judgeXY()
{
ev.clear(); S.clear();
for (int i = 1; i <= m; i++)
q[i] = Point(p[i].x - p[i].y, p[i].x + p[i].y);
for (int i = 1; i <= n; i++)
{
if (q[r[i]] < q[l[i]]) std::swap(l[i], r[i]);
if (q[l[i]].x != q[r[i]].x)
{
ev.push_back({l[i], i});
ev.push_back({r[i], -i});
}
}
return judge();
}
int main(int argc, char *argv[])
{
registerTestlibCmd(argc, argv);
n = inf.readInt();
for (int i = 1, p = n << 1; i <= p; i++) f[i] = i;
for (int i = 1; i <= n; i++)
{
int ax = inf.readInt(), ay = inf.readInt();
int bx = inf.readInt(), by = inf.readInt();
Point a(ax, ay), b(bx, by);
mp.insert({a, ++m}); p[m] = a; l[i] = m;
mp.insert({b, ++m}); p[m] = b; r[i] = m;
Union(m - 1, m);
}
for (int i = 1; i < n; i++)
{
int ax = ouf.readInt(), ay = ouf.readInt();
int bx = ouf.readInt(), by = ouf.readInt();
Point a(ax, ay), b(bx, by);
auto A = mp.find(a);
if (A == mp.end())
quitf(_wa, "(%d, %d) is not a city", ax, ay);
auto B = mp.find(b);
if (B == mp.end())
quitf(_wa, "(%d, %d) is not a city", bx, by);
Union(A -> second, B -> second);
l[i + n] = A -> second; r[i + n] = B -> second;
}
n <<= 1; --n;
for (int i = 2, fa = getf(1); i <= n; i++)
if (getf(i) != fa)
quitf(_wa, "City (%d, %d) is not connected.", p[i].x, p[i].y);
if (!judgeNoX())
{
quitf(_wa, "intersection which isn't an endpoint exists.");
}
if (!judgeNoY())
{
quitf(_wa, "intersection which isn't an endpoint exists.");
}
if (!judgeXY())
{
quitf(_wa, "intersection which isn't an endpoint exists.");
}
quitf(_ok, "OK");
return 0;
}
话说 LOJ 不是有吗