题目地址


基本思路:

  • 权值线段树+线段树合并+并查集. 

类似题目:

  • 雨天的尾巴

#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=1e7,INF=2e9;
struct Node{
	int ls,rs;
	int cnt;//被加次数 
	int pos;//岛屿编号 
}tr[MAXN];
int nodeCnt=0;//权值线段树 
int root[MAXN];
void insert(int &now,int l,int r,int x,int pos){
	if(!now)now=++nodeCnt;
	if(l==r){
		tr[now].cnt++;
		tr[now].pos=pos;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)insert(tr[now].ls,l,mid,x,pos);
	else insert(tr[now].rs,mid+1,r,x,pos);
	tr[now].cnt=tr[tr[now].ls].cnt+tr[tr[now].rs].cnt;
}
int merge(int p,int q,int l,int r){
	if(!p)return q;
	if(!q)return p;
	if(l==r){
		tr[p].cnt+=tr[q].cnt;
		tr[p].pos=tr[q].pos;
		return p;
	}
	int mid=(l+r)>>1;
	tr[p].ls=merge(tr[p].ls,tr[q].ls,l,mid);
	tr[p].rs=merge(tr[p].rs,tr[q].rs,mid+1,r);
	tr[p].cnt=tr[tr[p].ls].cnt+tr[tr[p].rs].cnt;
	return p;
}
int query(int now,int l,int r,int k){
	if(l==r)return tr[now].pos;
	if(tr[now].cnt<k)return -1;//不存在 
	int mid=(l+r)>>1;
	int lsum=tr[tr[now].ls].cnt;
	if(k<=lsum)return query(tr[now].ls,l,mid,k);
	else return query(tr[now].rs,mid+1,r,k-lsum);
}
int fa[MAXN];
int get(int x){
	while(x!=fa[x])x=fa[x]=fa[fa[x]];
	return x;
}
int b_merge(int a,int b){//集合合并 
	fa[get(a)]=get(b);
	return get(b);
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=n;i++){
		int rank;//重要度 
		scanf("%d",&rank);
		insert(root[i],-INF,INF,rank,i);
	}
	for(int i=1;i<=m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		a=get(a),b=get(b);
		int rt=merge(root[a],root[b],-INF,INF);
		b_merge(a,b);
		root[a]=root[b]=rt;
	}
	int q;
	scanf("%d",&q);//q个操作
	for(int i=1;i<=q;i++){
		char opt;
		cin>>opt;
		if(opt=='B'){
			int x,y;
			scanf("%d%d",&x,&y);//修一条新桥 
			x=get(x),y=get(y);
			int rt=merge(root[x],root[y],-INF,INF);
			b_merge(x,y);
			root[x]=root[y]=rt;
		}else if(opt=='Q'){
			int x,k;
			scanf("%d%d",&x,&k);
			cout<<query(root[get(x)],-INF,INF,k)<<endl; 
		}
	} 
	return 0;
}