洛谷 P3224 [HNOI2012]永无乡 题解--zhengjun

思路

十分板,直接上线段树分裂就行了,加上一个并查集维护一下联通情况就行了。

代码

#include<bits/stdc++.h>
using namespace std;typedef long long ll;const int N=1e5+10,P=1e7;char op[5];
int n,m,q,cnt,f[N],root[N],a[N],id[N];struct tree{int ls,rs,siz;}t[P];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void pushup(int rt){t[rt].siz=t[t[rt].ls].siz+t[t[rt].rs].siz;}
void update(int &rt,int cur,int l=1,int r=n){
	if(!rt)rt=++cnt;t[rt].siz++;if(l==r)return;int mid=(l+r)>>1;
	cur<=mid?update(t[rt].ls,cur,l,mid):update(t[rt].rs,cur,mid+1,r);
}
void merge(int &x,int y,int l=1,int r=n){
	if(!x||!y)return void(x|=y);int mid=(l+r)>>1;
	merge(t[x].ls,t[y].ls,l,mid);merge(t[x].rs,t[y].rs,mid+1,r);pushup(x);
}
int query(int rt,int k,int l=1,int r=n){
	if(l==r)return k>0&&k<=t[rt].siz?id[l]:-1;int mid=(l+r)>>1;
	return k<=t[t[rt].ls].siz?query(t[rt].ls,k,l,mid):query(t[rt].rs,k-t[t[rt].ls].siz,mid+1,r);
}
void link(int u,int v){if(find(u)!=find(v))merge(root[find(v)],root[find(u)]),f[find(u)]=find(v);}
int main(){
	scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&a[f[i]=i]),id[a[i]]=i,update(root[i],a[i]);
	for(int i=1,u,v;i<=m;i++)scanf("%d%d",&u,&v),link(u,v);scanf("%d",&q);for(int i=1,x,y;i<=q;i++){
		scanf("%s%d%d",op,&x,&y);if(op[0]=='Q')printf("%d\n",query(root[find(x)],y));else link(x,y);
	}return 0;
}

posted @ 2022-07-04 22:16  A_zjzj  阅读(20)  评论(0编辑  收藏  举报