bzoj1604
treap+并查集
我们能想到一个点和最近点对连接,用并查集维护,但是这个不仅不能求,而且还是不对的,于是就看了题解
把距离转为A(x-y,x+y),这样两点之间的距离就是max(x'-X',y'-Y'),那么就可以求了,我们按转换后的x排序,维护一个区间,最大的x和最小的x差不超过c,然后把y插进treap里,每次查找前驱后继,如果距离小于等于c就连接,最后扫一遍统计答案就行
曼哈顿和切比雪夫距离是可以互相转换的,x=x-y,y=x+y就行,切比雪夫距离转换为曼哈顿距离转换回去也可以
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N = 200010, seed = 19992147, inf = 2000000010; struct data { int x, y; data(int x = 0, int y = 0) : x(x), y(y) {} bool friend operator < (data A, data B) { return A.x < B.x; } } a[N]; int n, ans, root; long long c; pair<int, int> pre, nxt; int sum[N], fa[N]; struct Treap { int cnt, P; pair<int, int> key[N]; int size[N], child[N][2], p[N], tot[N]; inline int rand() { P = P * seed + 123456; return abs(P); } inline void update(int x) { size[x] = size[child[x][0]] + size[child[x][1]] + tot[x]; } inline void rotate(int &x, int t) { int y = child[x][t]; child[x][t] = child[y][t ^ 1]; child[y][t ^ 1] = x; update(x); update(y); x = y; } inline void insert(int &x, pair<int, int> o) { if(x == 0) { p[x = ++cnt] = rand(); key[x] = o; tot[x] = 1; } else { if(key[x] == o) ++tot[x]; else { int t = o > key[x]; insert(child[x][t], o); if(p[child[x][t]] > p[x]) rotate(x, t); } } update(x); } inline void erase(int &x, pair<int, int> o) { if(key[x] == o) { if(child[x][0] == 0 && child[x][1] == 0) { --tot[x]; if(tot[x] == 0) x = 0; else update(x); } else { int t = p[child[x][1]] > p[child[x][0]]; rotate(x, t); erase(child[x][t ^ 1], o); } } else erase(child[x][o > key[x]], o); update(x); } inline void query_pre(int x, pair<int, int> o) { if(x == 0) return; if(key[x] > o) query_pre(child[x][0], o); else { if(key[x] > pre) pre = key[x]; query_pre(child[x][1], o); } } inline void query_nxt(int x, pair<int, int> o) { if(x == 0) return; if(key[x] < o) query_nxt(child[x][1], o); else { if(key[x] < nxt) nxt = key[x]; query_nxt(child[x][0], o); } } } treap; inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } inline void connect(int x, int y) { int u = find(x), v = find(y); if(u == v) return; --ans; fa[v] = u; } int main() { // freopen("nabor.in", "r", stdin); // freopen("nabor.out", "w", stdout); scanf("%d%lld", &n, &c); ans = n; for(int i = 1; i <= n; ++i) { int x, y; scanf("%d%d", &x, &y); a[i] = data(x - y, x + y); } a[0].x = inf; sort(a + 1, a + n + 1); treap.insert(root, {-inf, -1}); treap.insert(root, {inf, -1}); for(int i = 1; i <= n; ++i) fa[i] = i; int l = 1; for(int i = 1; i <= n; ++i) { pair<int, int> o; while(l <= i && a[i].x - a[l].x > c) { o = make_pair(a[l].y, l); treap.erase(root, o); ++l; } nxt = {inf + 1, -1}; pre = {-inf - 1, -1}; o = make_pair(a[i].y, i); treap.query_pre(root, o); treap.query_nxt(root, o); long long dis_pre, dis_nxt; treap.insert(root, o); dis_pre = (long long)a[i].y - (long long)pre.first; dis_nxt = (long long)nxt.first - (long long)a[i].y; if(dis_pre <= c && pre.second != -1) connect(i, pre.second); if(dis_nxt <= c && nxt.second != -1) connect(i, nxt.second); } printf("%d ", ans); ans = 0; for(int i = 1; i <= n; ++i) ++sum[find(i)]; for(int i = 1; i <= n; ++i) ans = max(ans, sum[i]); printf("%d\n", ans); // fclose(stdin); // fclose(stdout); return 0; }