[HNOI2012]永无乡

题目大意

给出一张\(n\)个点的图,给出初始的联通信息

每个点都有一个独一无二的权值(在\(1 \sim n\)中)

接下来有两种操作:

\(Q\)操作:询问\(A\)所在联通块中权值第\(k\)大(不存在输出\(-1\)

\(B\)操作:联通\(X,Y\)

解题思路

一眼是平衡树裸题呀,但本文选择用动态开点线段树合并做,另外用并查集维护一下连通性

\(i\)棵线段树维护了\(i\)所在的联通块中权值在\(l \sim r\)的结点总数\(size\)

定义:\(find(x)\)\(x\)在并查集中的最远祖先(并查集基本操作)

我们约定\(i\)所在的联通块的信息保存在第\(find(i)\)棵线段树上

这意味着一个联通块有唯一确定的线段树在维护它

合并操作:

首先判断\(x,y\)是否已经联通(是否在并查集同一个最远祖先下),若已经联通就跳出

否则合并第\(find(x)\)\(find(y)\)棵线段树,并合并在\(root[find(x)]\)下(相当于把第\(find(y)\)棵线段树的信息附加到第\(find(x)\)棵上)

然后维护并查集的信息(常规\(Union\)操作)

询问操作:

因为\(A\)所在联通块信息保存在第\(find(A)\)棵线段树上,所以在第\(find(A)\)棵线段树上查找第\(k\)大即可(利用线段树维护的\(size\)信息)

#include<iostream>
#include<cstdio>

int n,m,imp[200000],reimp[200000];
char opt;
int x,y;

int B[200000];

struct node{
	int L,R,size;
}N[10000000];
int tot,root[200000];

void insert(int &st,int k,int l,int r){
	if (l>k||r<k) return;
	if (!st) st=++tot;
	if (l==r){N[st].size=1;return;}
	int mdl=(l+r)>>1;
	insert(N[st].L,k,l,mdl);
	insert(N[st].R,k,mdl+1,r);
	N[st].size=1;
}

int merge(int nowL,int nowR,int l,int r){
	if (!(nowL&&nowR)) return nowL|nowR;
	if (l>r) return 0;
	N[nowL].size+=N[nowR].size;
	int mdl=(l+r)>>1;
	N[nowL].L=merge(N[nowL].L,N[nowR].L,l,mdl);
	N[nowL].R=merge(N[nowL].R,N[nowR].R,mdl+1,r);
	return nowL;
}

int query(int now,int k,int l,int r){
	if (l==r) return reimp[l];
	int rank=N[N[now].L].size;
	int mdl=(l+r)>>1;
	if (k<=rank) return query(N[now].L,k,l,mdl);
	else return query(N[now].R,k-rank,mdl+1,r);
}

int find(int k){return (k==B[k])?(k):(B[k]=find(B[k]));}

int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++){
		scanf("%d",&imp[i]);
		insert(root[i],imp[i],1,n+1);
		reimp[imp[i]]=i;
	}
	for (int i=1;i<=n;i++) B[i]=i;
	for (int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		if (find(x)==find(y)) continue;
		root[find(y)]=merge(root[find(y)],root[find(x)],1,n+1);
		B[find(x)]=find(y);
	}
	scanf("%d\n",&m);
	for (int i=1;i<=m;i++){
		scanf("%c%d%d\n",&opt,&x,&y);
		if (opt=='Q'){
			int ans=query(root[find(x)],y,1,n+1);
			if (!ans) puts("-1");
			else printf("%d\n",ans);
		}
		else{
			if (find(x)==find(y)) continue;
			root[find(y)]=merge(root[find(y)],root[find(x)],1,n+1);
			B[find(x)]=find(y);
		}
	}
}
原文地址:https://www.cnblogs.com/ytxytx/p/9441019.html