2733: [HNOI2012]永无乡

传说中的启发式合并,就是选出n1logn2和n2logn1中的较小值(不要跟我提常数谢谢)

用平衡树维护一个联通块,我选的SBT(好高端的样子,煞笔树吗?),然后就是俩操作了:合并两棵树,查询一棵树内第k小的节点。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100000+5;
inline int read(){
	int x=0,f=1;char ch;
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int fa[N],pa[N],sz[N],lc[N],rc[N],key[N];
inline int find(int x){
	return pa[x]!=x?pa[x]=find(pa[x]):x;
}
inline void pushup(int x){sz[x]=sz[lc[x]]+sz[rc[x]]+1;}
inline int findroot(int x){
	while(fa[x])x=fa[x];
	return x;
}
inline void lturn(int &x){
	int k=rc[x];fa[lc[k]]=x;fa[k]=fa[x];fa[x]=k;rc[x]=lc[k];lc[k]=x;sz[k]=sz[x];pushup(x);x=k;
}
inline void rturn(int &x){
	int k=lc[x];fa[rc[k]]=x;fa[k]=fa[x];fa[x]=k;lc[x]=rc[k];rc[k]=x;sz[k]=sz[x];pushup(x);x=k;
}
inline void maintain(int &x,bool flag){
	if(!flag){
		if(sz[lc[lc[x]]]>sz[rc[x]])rturn(x);
		else if(sz[rc[lc[x]]]>sz[rc[x]]){
			lturn(lc[x]);
			rturn(x);
		}else return;
	}else{
		if(sz[rc[rc[x]]]>sz[lc[x]])lturn(x);
		else if(sz[lc[rc[x]]]>sz[lc[x]]){
			rturn(rc[x]);
			lturn(x);
		}else return;
	}
	maintain(lc[x],false);maintain(rc[x],true);
	maintain(x,true);maintain(x,false);
}
void ins(int &u,int v,int last){
	if(!u){u=v;lc[u]=rc[u]=0;sz[u]=1;fa[u]=last;}
	else{
		sz[u]++;
		if(key[v]<key[u])ins(lc[u],v,u);
		else ins(rc[u],v,u);
		maintain(u,key[v]>=key[u]);
	}
}
void mergeto(int src,int &dest){
	if(lc[src])mergeto(lc[src],dest);
	if(rc[src])mergeto(rc[src],dest);
	ins(dest,src,0);
}
void merge(int u,int v){
	u=find(u);v=find(v);
	if(u==v)return;
	int rootu=findroot(u),rootv=findroot(v);
	if(sz[rootu]<sz[rootv]){pa[u]=v;mergeto(rootu,rootv);}
	else {pa[v]=u;mergeto(rootv,rootu);}
}
int kth(int u,int k){
	int r=sz[lc[u]]+1;
	if(r==k)return u;
	else if(k<r)return kth(lc[u],k);
	else return kth(rc[u],k-r);
}
int main(){
	int n,m;n=read();m=read();
	int u,v;
	for(int i=1;i<=n;i++)pa[i]=i,key[i]=read(),sz[i]=1;
	for(int i=1;i<=m;i++){
		u=read();v=read();
		merge(u,v);
	}
	int q=read();char opt[10];
	while(q--){
		scanf("%s%d%d",opt,&u,&v);
		if(opt[0]=='B')merge(u,v);
		else{
			if(sz[findroot(u)]<v)printf("-1\n");
			else printf("%d\n",kth(findroot(u),v));
		}
	}
	return 0;
}


你可能感兴趣的:(2733: [HNOI2012]永无乡)