永无乡[Splay启发式合并]

题目描述

永无乡包含 nn 座岛,编号从 1 到 n ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 a 出发经过若干座(含0 座)桥可以 到达岛 b ,则称岛 a 和岛 b 是连通的。

现在有两种操作:

B x y 表示在岛 x 与岛 y 之间修建一座新桥。

Q x k 表示询问当前与岛 x 连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪座,请你输出那个岛的编号。

输入格式:

第一行是用空格隔开的两个正整数 n 和 m ,分别表示岛的个数以及一开始存在的桥数。

接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 ai​ 和 bi​ ,表示一开始就存在一座连接岛ai​ 和岛bi​ 的桥。

后面剩下的部分描述操作,该部分的第一行是一个正整数 q,表示一共有 q 个操作,接下来的 q 行依次描述每个操作,操作的 格式如上所述,以大写字母 Q 或 B 开始,后面跟两个不超过 n 的正整数,字母与数字以及两个数字之间用空格隔开。

输出格式:

对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 -1 。

输入样例#1: 

5  1
4  3 2 5 1
1  2
7
Q 3 2
Q 2 1
B 2 3
B 1 5
Q 2 1
Q 2 4
Q 2 3

输出样例#1: 

-1
2
5
1
2

对于 100% 的数据 n≤100000,m≤n,q≤300000


合并Splay+区间第k大

对于合并,我们把size小的一个点一个点拆开,然后插入到另一个里面

听起来很暴力,其实复杂度是正确的 

因为小的那个大小至少翻倍,所以一个元素最多查logn次

总的复杂度为O(nlongn^2)


#include<bits/stdc++.h>
#define N 100005
#define lc t[x].ch[0]
#define rc t[x].ch[1]
using namespace std;
struct Node{
    int ch[2],fa,size;
}t[N];
int n,m,q,rt[N],f[N],a[N],ans,tot;
char ch[20];
int read(){
    int cnt=0,f=1;char ch=0;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')f=-1;}
    while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
    return cnt*f;
}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void Pushup(int x){
	t[x].size=t[lc].size+t[rc].size+1;
}
void rotate(int x,int &goal){
	int y=t[x].fa,z=t[y].fa;
	int k=(t[y].ch[1]==x);
	if(y==goal) goal=x;
	t[z].ch[t[z].ch[1]==y]=x;
	t[x].fa=z;
	t[y].ch[k]=t[x].ch[k^1];
	t[t[x].ch[k^1]].fa=y;
	t[x].ch[k^1]=y;
	t[y].fa=x;
	Pushup(y),Pushup(x);
}
void splay(int x,int &goal){
	while(t[x].fa!=goal){
		int y=t[x].fa,z=t[y].fa;
		if(z!=goal)
			(t[y].ch[1]==x)^(t[z].ch[1]==y)?rotate(x,goal):rotate(y,goal);
		rotate(x,goal);
	}
}
void insert(int u,int &x,int fa){
    if(x==0){x=u;t[u].fa=fa;return;}
    t[x].size++;
    if(a[u]<=a[x]) insert(u,lc,x);
    else insert(u,rc,x);
}
void merge(int x,int y){
	if(x==y) return;
	if(t[rt[x]].size>t[rt[y]].size) swap(x,y);
	f[x]=y; 
	queue<int> q;
	q.push(rt[x]);
	while(!q.empty()){
		int u=q.front(); q.pop();
		if(t[u].ch[0]) q.push(t[u].ch[0]);
		if(t[u].ch[1]) q.push(t[u].ch[1]);
		insert(u,rt[y],0);
		splay(u,rt[y]);
	}
}
int Kth(int x,int k){
	if(t[lc].size>=k) return Kth(lc,k);
	else if(t[lc].size==k-1) return x;
	return Kth(rc,k-t[lc].size-1);
} 
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) f[i]=i,rt[i]=i,t[i].size=1;
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		merge(find(x),find(y));
	}
	q=read();
	while(q--){
		scanf("%s",ch);
		int x=read(),y=read();
		if(ch[0]=='Q'){
			x=rt[find(x)];
			if(t[x].size<y) printf("-1\n");
			else printf("%d\n",Kth(x,y));
		}
		if(ch[0]=='B') merge(find(x),find(y));
	}
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/83048118