[并查集+启发式合并]BZOJ 2733——[HNOI2012]永无乡

来源:互联网 发布:c语言排队系统 编辑:程序博客网 时间:2024/06/04 18:01

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;}
阅读全文
0 0