HDU 5820 Lights (2016多校7L,主席树)
题意 给定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;
}

浙公网安备 33010602011771号