P3224 [HNOI2012]永無鄉 權值線段樹合併

學了線段樹合併以後這題感覺瞬間水了,標籤是平衡樹,平衡樹合併還沒學的很會,不過線段樹合併絕對是最好寫的

用並查集維護連通性。注意 合併的時候並查集要與線段樹合併一致 假如fa[a]=b 那麼就要把a合併到b上面去 

另外的求第k大就是基礎操作了

#include<bits/stdc++.h>
#define R register int
using namespace std;
const int N = 1e5+10;
int fa[N],rt[N],lc[N*40],rc[N*40],sum[N*40],n,m,tot,q,val[N];
inline int in(){
	R w=0,x=0;char c=0;
	while(c<'0'||c>'9') w|=c=='-',c=getchar();
	while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return w?-x:x;
}
void update(R &o,R l,R r,R pos){
	o=++tot;sum[o]++;
	if(l==r) return;
	R mid = l+r>>1;
	if(pos<=mid) update(lc[o],l,mid,pos);
	else update(rc[o],mid+1,r,pos);
}
int merge(R x,R y){
	if(!x||!y) return x+y;
	sum[x]+=sum[y];
	lc[x]=merge(lc[x],lc[y]);
	rc[x]=merge(rc[x],rc[y]);
	return x;
}
int kth(R o,R l,R r,R k){
	if(l==r) return l;
	R mid = l+r>>1;
	if(sum[lc[o]]>=k) return kth(lc[o],l,mid,k);
	else return kth(rc[o],mid+1,r,k-sum[lc[o]]);
}
int getfa(int x){
	return x==fa[x]?x:fa[x]=getfa(fa[x]);
}
int main(){
	n=in();m=in();
	for(R i = 1; i <= n; i++){
		R x;
		x=in();
		update(rt[i],1,n,x);
		val[x]=i;
		fa[i]=i;
	}
	for(R i = 1; i <= m; i++){
		R u,v;
		u=in(),v=in();
		R x=getfa(u),y=getfa(v);
		if(x!=y){
			fa[y]=x;
			rt[x]=merge(rt[x],rt[y]);
		}
	}
	q=in();
	char op[3];
	R x,y;
	for(R i = 1; i <= q; i++){
		scanf("%s",op);
		x=in(),y=in();
		if(op[0]=='Q'){
			x=getfa(x);
			if(sum[rt[x]]<y) puts("-1");
			else printf("%d\n",val[kth(rt[x],1,n,y)]);
		}else{
			R u=getfa(x),v=getfa(y);
			if(u!=v){
				fa[v]=u;
				rt[u]=merge(rt[u],rt[v]);
			}
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章