[HNOI2012]永无乡

线段树合并,手打一遍过。

非常嗨皮,记录一下。

使用并查集,合并+查询。

代码如下:


#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,q,a[maxn],rev[maxn],f[maxn];
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
inline char getc(){
	char c=getchar();
	while(c<'A'||c>'Z')c=getchar();
	return c;
}
inline int find(int x){
	if(f[x]==x)return x;
	return f[x]=find(f[x]);
}
struct node{
	int val,lc,rc;
}tr[maxn*20];
int cnt,rt[maxn];
inline int modify(int h,int l,int r,int x){
	if(!h)h=++cnt;
	tr[h].val++;
	if(l==r)return h;
	int mid=(l+r)>>1;
	if(mid>=x)tr[h].lc=modify(tr[h].lc,l,mid,x);
	else tr[h].rc=modify(tr[h].rc,mid+1,r,x);
	return h;
}
inline int merge(int a,int b,int l,int r){
	if(!a)return b;
	if(!b)return a;
	tr[a].val+=tr[b].val;
	if(l==r)return a;
	int mid=(l+r)>>1;
	tr[a].lc=merge(tr[a].lc,tr[b].lc,l,mid);
	tr[a].rc=merge(tr[a].rc,tr[b].rc,mid+1,r);
	return a;
}
inline int query(int h,int l,int r,int x){
	if(l==r)return l;
	int mid=(l+r)>>1;
	if(tr[tr[h].lc].val>=x)return query(tr[h].lc,l,mid,x);
	else return query(tr[h].rc,mid+1,r,x-tr[tr[h].lc].val);
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)
		f[i]=i,a[i]=read(),rev[a[i]]=i;
	int x,y;
	for(int i=1;i<=m;i++){
		x=read(),y=read();
		if(find(x)!=find(y))
			f[find(x)]=find(y);
	}
	for(int i=1;i<=n;i++){
		int t=find(i);
		rt[t]=modify(rt[t],1,n,a[i]);
	}
	q=read();
	char opt;
	for(int i=1;i<=q;i++){
		opt=getc(),x=read(),y=read();
		if(opt=='Q')
			if(tr[rt[find(x)]].val>=y)printf("%d\n",rev[query(rt[find(x)],1,n,y)]);
			else puts("-1");
		else if(find(x)!=find(y)){
			rt[find(x)]=merge(rt[find(x)],rt[find(y)],1,n);
			f[find(y)]=find(x);
		}
	}
	return 0;
}

深深地感到自己的弱小。

posted @ 2020-06-16 21:58  syzf2222  阅读(135)  评论(0编辑  收藏  举报