[HNOI2012]永无乡
题目大意
给出一张\(n\)个点的图,给出初始的联通信息
每个点都有一个独一无二的权值(在\(1 \sim n\)中)
接下来有两种操作:
\(Q\)操作:询问\(A\)所在联通块中权值第\(k\)大(不存在输出\(-1\))
\(B\)操作:联通\(X,Y\)
解题思路
一眼是平衡树裸题呀,但本文选择用动态开点线段树合并做,另外用并查集维护一下连通性
第\(i\)棵线段树维护了\(i\)所在的联通块中权值在\(l \sim r\)的结点总数\(size\)
定义:\(find(x)\)为\(x\)在并查集中的最远祖先(并查集基本操作)
我们约定\(i\)所在的联通块的信息保存在第\(find(i)\)棵线段树上
这意味着一个联通块有唯一确定的线段树在维护它
合并操作:
首先判断\(x,y\)是否已经联通(是否在并查集同一个最远祖先下),若已经联通就跳出
否则合并第\(find(x)\)和\(find(y)\)棵线段树,并合并在\(root[find(x)]\)下(相当于把第\(find(y)\)棵线段树的信息附加到第\(find(x)\)棵上)
然后维护并查集的信息(常规\(Union\)操作)
询问操作:
因为\(A\)所在联通块信息保存在第\(find(A)\)棵线段树上,所以在第\(find(A)\)棵线段树上查找第\(k\)大即可(利用线段树维护的\(size\)信息)
#include<iostream>
#include<cstdio>
int n,m,imp[200000],reimp[200000];
char opt;
int x,y;
int B[200000];
struct node{
int L,R,size;
}N[10000000];
int tot,root[200000];
void insert(int &st,int k,int l,int r){
if (l>k||r<k) return;
if (!st) st=++tot;
if (l==r){N[st].size=1;return;}
int mdl=(l+r)>>1;
insert(N[st].L,k,l,mdl);
insert(N[st].R,k,mdl+1,r);
N[st].size=1;
}
int merge(int nowL,int nowR,int l,int r){
if (!(nowL&&nowR)) return nowL|nowR;
if (l>r) return 0;
N[nowL].size+=N[nowR].size;
int mdl=(l+r)>>1;
N[nowL].L=merge(N[nowL].L,N[nowR].L,l,mdl);
N[nowL].R=merge(N[nowL].R,N[nowR].R,mdl+1,r);
return nowL;
}
int query(int now,int k,int l,int r){
if (l==r) return reimp[l];
int rank=N[N[now].L].size;
int mdl=(l+r)>>1;
if (k<=rank) return query(N[now].L,k,l,mdl);
else return query(N[now].R,k-rank,mdl+1,r);
}
int find(int k){return (k==B[k])?(k):(B[k]=find(B[k]));}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",&imp[i]);
insert(root[i],imp[i],1,n+1);
reimp[imp[i]]=i;
}
for (int i=1;i<=n;i++) B[i]=i;
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if (find(x)==find(y)) continue;
root[find(y)]=merge(root[find(y)],root[find(x)],1,n+1);
B[find(x)]=find(y);
}
scanf("%d\n",&m);
for (int i=1;i<=m;i++){
scanf("%c%d%d\n",&opt,&x,&y);
if (opt=='Q'){
int ans=query(root[find(x)],y,1,n+1);
if (!ans) puts("-1");
else printf("%d\n",ans);
}
else{
if (find(x)==find(y)) continue;
root[find(y)]=merge(root[find(y)],root[find(x)],1,n+1);
B[find(x)]=find(y);
}
}
}