您的位置:首页 > 其它

[平衡树+启发式合并] 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: