• 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
    ", ans);
    //    fclose(stdin);
    //    fclose(stdout);
        return 0;
    }
    View Code
  • 相关阅读:
    如何快速定位到DBGrid的某一行!!!急...
    说说设计模式~单件模式(Singleton)
    EF架构~终于自己架构了一个相对完整的EF方案
    .Net——实现IConfigurationSectionHandler接口定义处理程序处理自定义节点
    在LINQ中实现多条件联合主键LEFT JOIN
    从LINQ开始之LINQ to Objects(上)
    WPF控件模板和数据模板
    WPF的ListView控件自定义布局用法实例
    初步探讨WPF的ListView控件(涉及模板、查找子控件)
    LINQ技巧:如何通过多次调用GroupBy实现分组嵌套
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7421464.html
Copyright © 2020-2023  润新知