bzoj 2733 永无乡 Splay 启发式合并

来源:互联网 发布:上海进项发票认证软件 编辑:程序博客网 时间:2024/05/21 04:17

题目大意:n(n<=10w)个点,每个点都有重要度,q(q<=30w)个操作。1.每次连接2个点。2.查询a,k;与a相连的第k重要是哪一个点,不存在输出-1。
查询可以Splay搞,修改暴力启发式合并,因为每次合并size翻倍,所以每个点最多被合并logn次。复杂度nlog²n。

#include<cstdio>#include<iostream>#include<cstdlib>#define maxn 100005using namespace std;int fa[maxn];int ch[maxn][2];int sz[maxn];int key[maxn];bool dir(int x){return x==ch[fa[x]][1];}void up(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}void rotate(int x){    bool b=dir(x);    int y=fa[x];    int z=fa[y];    int a=ch[x][!b];    if(z)ch[z][dir(y)]=x;    fa[x]=z;ch[y][b]=a;    fa[y]=x;ch[x][!b]=y;    if(a!=0) fa[a]=y;    up(y);up(x);}void splay(int x){    while(fa[x])    {        int y=fa[x];int z=fa[y];        if(z==0)            rotate(x);        else        {            bool b=dir(x);            bool c=dir(y);            if(b^c) {rotate(x);rotate(x);}            else    {rotate(y);rotate(x);}        }    }}int lass;void insert(int x,int k,int last){    if(k==0)    {        fa[x]=last;        if(key[x]<key[last])             ch[last][0]=x;        else ch[last][1]=x;        splay(x);        lass=x;        return ;    }    if(key[x]<key[k])        insert(x,ch[k][0],k);    else        insert(x,ch[k][1],k);}int rank_num(int x,int k){    if(sz[ch[x][0]]+1==k)        return x;    if(sz[ch[x][0]]>=k)        return rank_num(ch[x][0],k);    return rank_num(ch[x][1],k-sz[ch[x][0]]-1);}int F[maxn];int find(int x){return F[x]==x?x:F[x]=find(F[x]);}void dfs(int x,int y){    int q=ch[x][0],w=ch[x][1];    ch[x][0]=0;ch[x][1]=0;    insert(x,y,0);    if(q)dfs(ch[x][0],lass);    if(w)dfs(ch[x][1],lass);}char s[3];int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        sz[i]=1;        scanf("%d",&key[i]);        F[i]=i;    }    int x,y;    for(int i=1;i<=m;i++)    {        scanf("%d%d",&x,&y);        if(find(x)!=find(y))        {            F[find(x)]=find(y);            splay(x);splay(y);            if(sz[x]>sz[y])dfs(y,x);            else    dfs(x,y);        }    }    int q;scanf("%d",&q);    char c;    for(int i=1;i<=q;i++)    {        scanf("%s",s);        scanf("%d%d",&x,&y);        if(s[0]=='B')        {            if(find(x)!=find(y))            {                F[find(x)]=find(y);                splay(x);splay(y);                if(sz[x]>sz[y])                    dfs(y,x);                else                    dfs(x,y);            }        }         if(s[0]=='Q')        {            splay(x);            if(y>sz[x])                printf("-1\n");            else                printf("%d\n",rank_num(x,y));        }    }    return 0;}
3 0
原创粉丝点击