[平衡树+启发式合并] BZOJ2733: [HNOI2012]永无乡

来源:互联网 发布:mac 文稿占用空间 编辑:程序博客网 时间:2024/05/23 19:22

题意

永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。

题解

数据结构练手水题。
注意到只有合并操作,很容易想到对于每个联通块建平衡树,然后不断启发式合并。
据说splay启发式合并是nlogn?

#include<cstdio>#include<algorithm>using namespace std;struct node{    int key,id,size; node* ch[2];    node(int x=0,int y=0,node* son=NULL){ key=x; id=y; size=1; ch[0]=ch[1]=son; }    int cmp(int k){        if(key==k) return -1;        return key<k?1:0;    }    void maintain(){ size=ch[0]->size+ch[1]->size+1; }} nil, *null=&nil;typedef node* P_node;void init_null(){ null->size=0; null->ch[0]=null->ch[1]=null; }void rot(P_node &p,int d){    P_node k=p->ch[d^1]; p->ch[d^1]=k->ch[d]; k->ch[d]=p;    p->maintain(); k->maintain(); p=k;}void splay(P_node &p,int tkey){    int d1=p->cmp(tkey);    if(d1!=-1){        P_node p2=p->ch[d1]; int d2=p2->cmp(tkey);        if(d2!=-1){            splay(p2->ch[d2],tkey);            if(d1==d2) rot(p,d1^1), rot(p,d2^1);                  else rot(p->ch[d1],d2^1), rot(p,d1^1);         } else rot(p,d1^1);    }}void Insert(P_node &p,int tkey,int id){    if(p==null) p=new node(tkey,id,null);           else Insert(p->ch[p->key<tkey],tkey,id);    p->maintain();}int Kth(P_node p,int k){    if(p->ch[0]->size==k-1) return p->id;    if(p->ch[0]->size>=k) return Kth(p->ch[0],k);    return Kth(p->ch[1],k-p->ch[0]->size-1);}const int maxn=100005;int fa[maxn],w[maxn],c[maxn];P_node rt[maxn];void Print(P_node p){    if(p==null) return;    Print(p->ch[0]); c[++c[0]]=p->id; Print(p->ch[1]);    delete p;}int getfa(int x){ return fa[x]==x?x:fa[x]=getfa(fa[x]); }void Merge(int x,int y){    if(getfa(x)==getfa(y)) return;    P_node p1=rt[getfa(x)], p2=rt[getfa(y)];    if(p1->size<p2->size) swap(p1,p2);     c[0]=0; Print(p2);    for(int i=1;i<=c[0];i++) Insert(p1,w[c[i]],c[i]), splay(p1,w[c[i]]);    x=getfa(x); y=getfa(y); rt[fa[x]=y]=p1;}int getint(){    char ch=getchar(); int res=0,ff=1;    while(!('0'<=ch&&ch<='9')){ if(ch=='-') ff=-1; ch=getchar(); }    while('0'<=ch&&ch<='9') res=res*10+ch-'0', ch=getchar();    return res*ff;}int n,m,Q;int main(){    freopen("bzoj2733.in","r",stdin);    freopen("bzoj2733.out","w",stdout);    init_null();    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) w[i]=getint(), fa[i]=i, rt[i]=new node(w[i],i,null);    for(int i=1;i<=m;i++){        int x=getint(),y=getint();        Merge(x,y);    }    scanf("%d",&Q);    while(Q--){        char ch=getchar(); while(ch!='B'&&ch!='Q') ch=getchar();        int x=getint(),y=getint();        if(ch=='B') Merge(x,y); else{            if(rt[getfa(x)]->size<y) printf("-1\n"); else{                int res=Kth(rt[getfa(x)],y); splay(rt[getfa(x)],w[res]);                printf("%d\n",res);            }        }    }    return 0;}
0 0