P3224 [HNOI2012]永无乡(线段树合并)
支持加边和询问连通块第k大点权。
线段树合并即可。
//线段树合并
//每次合并两个连通块的权值线段树
//询问第k大
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int M=maxn*100;
int c[M],lson[M],rson[M],T[maxn],tot;
void pushup (int newRoot) {
c[newRoot]=c[lson[newRoot]]+c[rson[newRoot]];
}
int up (int i,int l,int r,int p,int v) {
int newRoot=i;
if (!newRoot) newRoot=++tot;
if (l==r) {
c[newRoot]+=v;
return newRoot;
}
int mid=(l+r)>>1;
if (p<=mid) lson[newRoot]=up(lson[newRoot],l,mid,p,v);
if (p>mid) rson[newRoot]=up(rson[newRoot],mid+1,r,p,v);
pushup(newRoot);
return newRoot;
}
int merge (int x,int y,int l,int r) {
if (!x) return y;
if (!y) return x;
if (l==r) {
c[x]+=c[y];
return x;
}
int mid=(l+r)>>1;
lson[x]=merge(lson[x],lson[y],l,mid);
rson[x]=merge(rson[x],rson[y],mid+1,r);
pushup(x);
return x;
}
int kth (int u,int l,int r,int k) {
//在一颗权值树上找第k大
if (l==r) return l;
int mid=(l+r)>>1;
if (c[lson[u]]<k) {
return kth(rson[u],mid+1,r,k-c[lson[u]]);
}
else {
return kth(lson[u],l,mid,k);
}
}
int father[maxn],n,m,sz[maxn];
int findfather (int x) {
int a=x;
while (x!=father[x]) x=father[x];
while (a!=father[a]) {
int z=a;
a=father[a];
father[z]=x;
}
return x;
}
int p[maxn];
int b[maxn];
int main () {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) father[i]=i,sz[i]=1;
for (int i=1;i<=n;i++) scanf("%d",p+i),b[p[i]]=i;
for (int i=1;i<=n;i++) T[i]=up(T[i],1,n,p[i],1);
while (m--) {
int x,y;
scanf("%d%d",&x,&y);
x=findfather(x);
y=findfather(y);
if (x==y) continue;
father[x]=y;
sz[y]+=sz[x];
T[y]=merge(T[y],T[x],1,n);
}
int q;
scanf("%d",&q);
while (q--) {
string op;
cin>>op;
if (op=="Q") {
int x,y;
scanf("%d%d",&x,&y);
x=findfather(x);
if (y>sz[x]) printf("-1\n");
else printf("%d\n",b[kth(T[x],1,n,y)]);
}
else {
int x,y;
scanf("%d%d",&x,&y);
x=findfather(x);
y=findfather(y);
if (x==y) continue;
father[x]=y;
sz[y]+=sz[x];
T[y]=merge(T[y],T[x],1,n);
}
}
}