题意 给定n个平面上的点,坐标范围为[1, 50000]。如果对于任意两个点,都可以通过直走(中途经过其他点)走到。
那么输出YES,否则输出NO。
首先排序,去重。
我们要找的点对是只能斜对角走到的点。
那么找到这个点正左边的离他最近的点和正上方最近的点。查询以这三个点为顶点的矩形的内部有没有其他点。
如果有的话就找到了这样的点对,输出NO。
用主席树实现,时间复杂度$O(nlogn)$。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; typedef pair <int, int> PII; const int N = 1e6 + 10; const int M = 5e4 + 10; PII a[N]; map <PII, int> mp; int n, flag; int T; int num; int mx[M], my[M]; int tot; int s[N << 3], ls[N << 3], rs[N << 3]; int root[M]; void update(int &x, int y, int l, int r, int pos){ x = ++tot; s[x] = s[y] + 1; if (l == r) return; ls[x] = ls[y]; rs[x] = rs[y]; int mid = (l + r) >> 1; if (pos <= mid) update(ls[x], ls[y], l, mid, pos); else update(rs[x], rs[y], mid + 1, r, pos); } int query(int x, int y, int L, int R, int l, int r){ if (l <= L && R <= r) return s[y] - s[x]; int ret = 0; int mid = (L + R) >> 1; if (l <= mid) ret += query(ls[x], ls[y], L, mid, l, r); if (r > mid) ret += query(rs[x], rs[y], mid + 1, R, l, r); return ret; } void work1(){ tot = 0; memset(mx, 0, sizeof mx); memset(my, 0, sizeof my); memset(root, 0, sizeof root); int last = root[0]; rep(i, 1, n){ int x1 = a[i].fi, y1 = a[i].se; int x2 = a[my[y1]].fi, y2 = a[mx[x1]].se; update(root[x1], last, 1, 50000, y1); int cnt = query(root[x2], root[x1], 1, 50000, y2 + 1, y1); if (cnt != 1){ flag = 0; return; } mx[a[i].fi] = i; my[a[i].se] = i; last = root[x1]; } } int main(){ while (~scanf("%d", &n), n){ rep(i, 1, n){ scanf("%d%d", &a[i].fi, &a[i].se); } a[n + 1].fi = a[n + 1].se = 0; sort(a + 1, a + n + 1); n = unique(a + 1, a + n + 1) - a - 1; flag = 1; work1(); rep(i, 1, n) a[i].fi = 50001 - a[i].fi; sort(a + 1, a + n + 1); work1(); puts(flag ? "YES" : "NO" ); } return 0; }