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就行,切比雪夫距离转换为曼哈顿距离转换回去也可以

#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;
}
View Code

 

posted @ 2017-08-24 09:41  19992147  阅读(132)  评论(0编辑  收藏  举报