[平衡树+启发式合并] BZOJ2733: [HNOI2012]永无乡
2017-04-16 15:57
232 查看
题意
永无乡包含 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; }
相关文章推荐
- 【pb_ds】【平衡树启发式合并】【并查集】bzoj2733 [HNOI2012]永无乡
- BZOJ2733 [HNOI2012]永无乡 平衡树启发式合并
- 【BZOJ2733】永无乡(HNOI2012)-平衡树启发式合并
- [BZOJ2733][HNOI2012][启发式合并][平衡树]永无乡
- [BZOJ2733][HNOI2012]永无乡(平衡树+启发式合并)
- BZOJ2733: [HNOI2012]永无乡 Splay启发式合并
- [BZOJ2733][HNOI2012]永无乡(并查集+splay启发式合并)
- bzoj2733: [HNOI2012]永无乡 启发式合并
- ☆ [HNOI2012] 永无乡 「平衡树启发式合并」
- 【BZOJ2733】【HNOI2012】永无乡(Splay启发式合并)
- bzoj2733 [HNOI2012]永无乡(splay启发式合并)
- BZOJ 2733 HNOI 2012 永无乡 平衡树启发式合并
- 【BZOJ2733】[HNOI2012]永无乡【启发式合并】【Splay】
- 【BZOJ2733】永无乡[HNOI2012](splay启发式合并or线段树合并)
- bzoj2733: [HNOI2012]永无乡 splay+启发式合并
- 【bzoj2733】[HNOI2012]永无乡 Treap启发式合并
- 【HNOI2012】永无乡(splay,启发式合并)
- BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]
- [bzoj2733][HNOI2012]永无乡 线段树合并+并查集
- BZOJ2773(HNOI2012)[永无乡]--Splay启发式合并