Ps:又水听博主解释一下:昨天模拟赛遇到启发式的裸题,愣是打成左偏树的合并,惭愧惭愧。于是今天找到裸题练习一下。
题目梗概
有n个节点,每个节点有一个独一无二的权值。
合并一些节点。
询问一个节点所在联通块的权值第k大的节点,不存在则输出-1。
解题思路
什么SB题
这显然是平衡树的一道模板题,并且涉及到启发式合并。
启发式合并听着高大上其实是非常暴力过程。
当两棵平衡树合并时,把节点数较少的平衡树拆开,一个个插入到节点数较多的平衡树。
效率:最坏的情况是两棵树一样大,那么每个节点最多插入了
log2n
次。
博主写的是treap,两个
log
。
还有因为每次需要获取每个联通块的祖先,需要并查集搞一搞。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
struct jz{
int x,r,s,id;
jz* son[2];
};
jz a[maxn*100],*null=a,*til=a,*ro[maxn];
int n,m,f[maxn],Q;
inline int _read(){
int num=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
return num;
}
jz* newnode(int x,int id){
til++;til->x=x;til->s=1;til->id=id;til->r=rand();
til->son[0]=til->son[1]=null;
return til;
}
void updata(jz* x){x->s=x->son[0]->s+x->son[1]->s+1;}
void turn(jz* &x,int d){
jz* t=x->son[d];x->son[d]=t->son[d^1];t->son[d^1]=x;
t->s=x->s;updata(x);x=t;
}
void Insert(jz* &x,int y,int id){
if (x==null){x=newnode(y,id);return;}
x->s++;
if (y<x->x){
Insert(x->son[0],y,id);
if (x->son[0]->r<x->r) turn(x,0);
}else{
Insert(x->son[1],y,id);
if (x->son[1]->r<x->r) turn(x,1);
}
}
int kth(jz* x,int k){
if (x->son[0]->s<k&&k<=x->son[0]->s+1) return x->id;else
if (k<=x->son[0]->s) return kth(x->son[0],k);else
return kth(x->son[1],k-x->son[0]->s-1);
}
void merge(jz* &x,jz* y){
if (y==null) return;
Insert(x,y->x,y->id);
merge(x,y->son[0]);merge(x,y->son[1]);
}
int get(int x){
if (f[x]==x) return x;
f[x]=get(f[x]);
return f[x];
}
void add(int x,int y){
if (ro[x]->s<ro[y]->s) swap(x,y);
if (x!=y) merge(ro[x],ro[y]),f[y]=x;
}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
n=_read(),m=_read();
for (int i=1;i<=n;i++) ro[i]=newnode(_read(),i),f[i]=i;
for (int i=1;i<=m;i++){
int x=get(_read()),y=get(_read());
if (x||y) add(x,y);
}
Q=_read();
while (Q--){
char ch=getchar();
while (ch!='Q'&&ch!='B') ch=getchar();
if (ch=='Q'){
jz* fa=ro[get(_read())];int y=_read();
if (fa->s<y) printf("-1\n");else printf("%d\n",kth(fa,y));
}else{
int x=get(_read()),y=get(_read());
add(x,y);
}
}
return 0;
}