1. 程式人生 > >[BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的鄰居 (Treap+單調隊列)

[BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的鄰居 (Treap+單調隊列)

find 你會 tree pri max pre 判斷 喜歡 -a

題面

了解奶牛們的人都知道,奶牛喜歡成群結隊.觀察約翰的N(1≤N≤100000)只奶牛,你會發現她們已經結成了幾個“群”.每只奶牛在吃草的時候有一個獨一無二的位置坐標Xi,Yi(l≤Xi,Yi≤[1..10^9];Xi,Yi∈整數.當滿足下列兩個條件之一,兩只奶牛i和j是屬於同一個群的:

1.兩只奶牛的曼哈頓距離不超過C(1≤C≤10^9),即lXi – xil+IYi – Yil≤C.

2.兩只奶牛有共同的鄰居.即,存在一只奶牛k,使i與k,j與k均同屬一個群.

? 給出奶牛們的位置,請計算草原上有多少個牛群,以及最大的牛群裏有多少奶牛

分析

觀察\(|x_i-x_j|+|y_i-y_j| \leq C\)

,發現這個式子和x,y都有關,不便維護

我們將點(x,y)變成(X,Y),其中X=x+y,Y=x-y,那麽之後兩點間的距離就可以寫成\(max(|X_i-X_j|,|Y_i-Yj|)\)

設兩點坐標為\((x_1,y_1),(x_2,y_2)\),變形之後就變成了\((x_1+y_1,x_1-y_1)(x_2+y_2,x_2-y_2)\),那麽\(|X_i-X_j|=|(x_1-x_2)+(y_1-y_2)|,|Y_i-Yj|=|(x_1-x_2)+(y_2-y_1)|\)。討論x,y的大小關系即可證明,這裏不再贅述

經過上面的轉化,我們現在只要保證\(max(|X_i-X_j|,|Y_i-Yj|) \leq C\)

,即\(|X_i-X_j| \leq C,|Y_i-Yj| \leq C\)

因此我們按X[i]從小到大把點排序,然後維護一個隊列,滿足\(X_{tail}-X_{head} \leq C\),否則就將head出隊。那麽Y的條件怎麽滿足呢。我們維護一棵平衡樹存儲當前隊列裏的所有點的Y坐標,然後對於新插入的\(Y_{tail}\),我們在平衡樹裏查找它的前驅和後繼,判斷它們的距離是否<=C,如果是,就將它們的編號合並(用一個並查集)

最後在並查集裏查找即可

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define maxn 100005
#define INF 0x7fffffff
using namespace std;
int n,c;
struct point{
    int x;
    int y;
    int id;
    point(){
        
    }
    point(int xx,int yy,int i){
        x=xx;
        y=yy;
        id=i;
    }
    friend bool operator < (point p,point q){
        return p.x<q.x;
    }
};
point a[maxn],q[maxn*2];
int head=0,tail=0;

struct value{
    int v;
    int id;
    value(){
        
    }
    value(int y,int i){
        v=y;
        id=i;
    }
    friend bool operator < (value p,value q){
        if(p.v==q.v) return p.id<q.id;
        return p.v<q.v;
    } 
    friend bool operator <= (value p,value q){
        return p==q||p<q;
    } 
    friend bool operator > (value p,value q){
        if(p.v==q.v) return p.id>q.id;
        return p.v>q.v;
    } 
    friend bool operator >= (value p,value q){
        return p>q||p==q;
    } 
    friend bool operator == (value p,value q){
        return p.id==q.id&&p.v==q.v;
    }
};
struct treap{
    struct node{
        int ls;
        int rs;
        int cnt;
        int sz;
        value val;
        int dat; 
    }tree[maxn];
    int root;    
    int ptr;
    int New(value val){
        ptr++;
        tree[ptr].ls=tree[ptr].rs=0;
        tree[ptr].cnt=tree[ptr].sz=1;
        tree[ptr].val=val;
        tree[ptr].dat=rand();
        return ptr;
    }
    void push_up(int x){
        tree[x].sz=tree[tree[x].ls].sz+tree[tree[x].rs].sz+tree[x].cnt;
    }
    void rturn(int &x){
        int y=tree[x].ls;
        tree[x].ls=tree[y].rs;
        tree[y].rs=x;
        x=y;
        push_up(tree[x].rs);
        push_up(x);
    }
    void lturn(int &x){
        int y=tree[x].rs;
        tree[x].rs=tree[y].ls;
        tree[y].ls=x;
        x=y;
        push_up(tree[x].ls);
        push_up(x);
    }
    void insert(int &x,value val){
        if(x==0){
            x=New(val);
            return;
        } 
        if(tree[x].val==val){
            tree[x].cnt++;
            push_up(x);
            return;
        }
        if(val<tree[x].val){
            insert(tree[x].ls,val);
            if(tree[tree[x].ls].dat>tree[x].dat){
                rturn(x);
            } 
        }else{
            insert(tree[x].rs,val);
            if(tree[tree[x].rs].dat>tree[x].dat){
                lturn(x);
            } 
        }
        push_up(x);
    }
    value get_pre(int x,value val){
        if(x==0) return value(-INF,0);
        if(tree[x].val>val) return get_pre(tree[x].ls,val);
        else return max(tree[x].val,get_pre(tree[x].rs,val)); 
    }
    value get_nex(int x,value val){
        if(x==0) return value(INF,0);
        if(tree[x].val<val) return get_nex(tree[x].rs,val);
        else return min(tree[x].val,get_nex(tree[x].ls,val)); 
    }
    void del(int &x,value val){
        if(x==0) return;
        if(tree[x].val==val){
            if(tree[x].cnt>1){ 
                tree[x].cnt--;
                push_up(x);
                return;
            }else{
                if(tree[x].ls||tree[x].rs){
                    if(tree[x].rs==0||tree[tree[x].ls].dat>tree[tree[x].rs].dat){
                        rturn(x);
                        del(tree[x].rs,val);
                    }
                    else{
                        lturn(x); 
                        del(tree[x].ls,val);
                    }
                    push_up(x);
                }else x=0;
                return;
            } 
        }
        if(val<tree[x].val) del(tree[x].ls,val);
        else del(tree[x].rs,val);
        push_up(x);
    }
}T; 

struct DSU{
    int fa[maxn];
    int cnt[maxn];
    void ini(int n){
        for(int i=1;i<=n;i++) fa[i]=i;
    }
    int find(int x){
        if(fa[x]==x) return x;
        else return fa[x]=find(fa[x]);
    }
    void merge(int x,int y){
        int fx=find(x);
        int fy=find(y);
        if(fx==fy) return;
        fa[find(x)]=find(y);
        tot--;
    } 
}S;
int main(){
//  freopen("2.in","r",stdin);
    int x,y;
    scanf("%d %d",&n,&c);
    for(int i=1;i<=n;i++){
        scanf("%d %d",&x,&y);
        a[i].x=x+y;
        a[i].y=x-y;
        a[i].id=i;
    }
    sort(a+1,a+1+n);
    S.ini(n);
    for(int i=1;i<=n;i++){
        while(head<tail&&a[i].x-q[head].x>c){
            T.del(T.root,value(q[head].y,q[head].id));
            head++;
        }
        value pre=T.get_pre(T.root,value(a[i].y,a[i].id));
        value nex=T.get_nex(T.root,value(a[i].y,a[i].id));
        if(pre.v!=-INF&&a[i].y-pre.v<=c) S.merge(a[i].id,pre.id);
        if(nex.v!=INF&&nex.v-a[i].y<=c) S.merge(a[i].id,nex.id);
        q[tail++]=a[i];
        T.insert(T.root,value(a[i].y,a[i].id));
    }
    for(int i=1;i<=n;i++){
        int f=S.find(i);
        S.cnt[f]++;
    }
    int ans=0,tot=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,S.cnt[i]);
    }
    sort(S.fa+1,S.fa+1+n);
    tot=unique(S.fa+1,S.fa+1+n)-S.fa-1;
    printf("%d %d\n",tot,ans);
}

[BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的鄰居 (Treap+單調隊列)