bzoj1861

splay

1操作:从平衡树中取出这个数,把rank改成最小,再insert进去

2操作:从平衡树中取出这个数,把rank改成最大,再insert进去

3操作:取出x和它相邻的数(1是右相邻,-1是左相邻,0直接continue)

4操作:查询x的rank

5操作:查询rank=x的数

/**************************************************************

    Problem: 1861

    User: syh0313

    Language: C++

    Result: Accepted

    Time:2616 ms

    Memory:22776 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

using namespace std;

const int maxn=500010;

int n,m,root,topt,rk[maxn],ch[2][maxn],fa[maxn],cnt[maxn],si[maxn],key[maxn],up,down,rkto[4*maxn];

char s[20];

void updata(int x){si[x]=si[ch[0][x]]+si[ch[1][x]]+cnt[x];}

void clear(int x) {rkto[rk[key[x]]]=0; rk[key[x]]=0; ch[0][x]=ch[1][x]=fa[x]=cnt[x]=si[x]=key[x]=0;}

int get(int x) {return (x==ch[1][fa[x]]);}

void ptf(int x)

{

    if (ch[0][x]) printf("%d %d\n",x,ch[0][x]),ptf(ch[0][x]);

    if (ch[1][x]) printf("%d %d\n",x,ch[1][x]),ptf(ch[1][x]);

}

void rotate(int x)

{

    int old=fa[x],oldfa=fa[old]; int wh=get(x);

    ch[wh][old]=ch[wh^1][x]; fa[ch[wh^1][x]]=old;

    ch[wh^1][x]=old; fa[old]=x; fa[x]=oldfa; if (oldfa) ch[ch[1][oldfa]==old][oldfa]=x;

    updata(old); updata(x);

}

void splay(int x)

{

    for (int ffa;(ffa=fa[x]);rotate(x))

    if (fa[ffa]) rotate((get(x)==get(ffa)?ffa:x));

    root=x;

}

void insert(int x)

{

    if (!root)

    {

        root=++topt; ch[0][topt]=ch[1][topt]=fa[topt]=0; cnt[topt]=si[topt]=1;

        key[topt]=x; return;

    }

    int now=root;

    while (1)

    {

        if (key[now]==x) {cnt[now]++; updata(now); updata(fa[now]); splay(now); return;}

        else if (rk[x]<rk[key[now]])

        {

            if (ch[0][now]) now=ch[0][now];

            else

            {

                ch[0][now]=++topt; ch[0][topt]=ch[1][topt]=0; fa[topt]=now;

                key[topt]=x; si[topt]=cnt[topt]=1; updata(fa[topt]); splay(topt); return;

            }

        }

        else

        {

            if (ch[1][now]) now=ch[1][now];

            else

            {

                ch[1][now]=++topt; ch[0][topt]=ch[1][topt]=0; fa[topt]=now;

                key[topt]=x; si[topt]=cnt[topt]=1; updata(fa[topt]); splay(topt); return;

            }

        }

    }

}

void del(int x)

{

    int now=root;

    while (1)

    {

        if (key[now]==x) break;

        if (rk[x]<=rk[key[now]]) now=ch[0][now];else now=ch[1][now];

    }

    splay(now); int old=root,rs=ch[1][root];

    if (cnt[root]>1) {cnt[root]--; si[root]--; return;}

    if (!ch[0][root] && !ch[1][root]) {clear(root); root=0; return;}

    if (!ch[0][root]) {int k=ch[1][root]; clear(root); root=k; fa[root]=0; return;}

    if (!ch[1][root]) {int k=ch[0][root]; clear(root); root=k; fa[root]=0; return;}

    now=ch[0][root]; while (ch[1][now]) {now=ch[1][now];}

    splay(now); ch[1][root]=rs;  fa[rs]=root; clear(old); updata(root);

return;

}

int find2(int x)

{

    int now=root;

    while (1)

    {

        if (key[now]==x) break;

        if (rk[key[now]]>=rk[x]) now=ch[0][now];

        else if (rk[key[now]]<rk[x]) now=ch[1][now];

    }

    splay(now);

return now;

}

int findth(int x)

{

    int now=root;

    while (1)

    {

        if (si[ch[0][now]]+cnt[now]>=x && si[ch[0][now]]<x) break;

        else if (si[ch[0][now]]>=x) now=ch[0][now];

        else if (si[ch[0][now]]+cnt[now]<x) {x-=si[ch[0][now]]+cnt[now]; now=ch[1][now];}

    }

    splay(now);

return key[now];

}

int find(int x)

{

    int now=root,ans=0;

    while (1)

    {

        if (key[now]==x) {ans+=si[ch[0][now]]; break;}

        if (rk[key[now]]>=rk[x]) now=ch[0][now];

        else if (rk[key[now]]<rk[x]) {ans+=si[ch[0][now]]+cnt[now]; now=ch[1][now];}

    }

    splay(now);

return ans;

}

int read()

{

    int xx=0,ff=1; char c=getchar();

    while (c<'0' || c>'9') {if (c=='-') ff=-1; c=getchar();}

    while (c>='0' && c<='9') {xx=(xx<<1)+(xx<<3)+c-'0'; c=getchar();}

return xx*ff;

}

int main()

{

    n=read(); m=read(); up=down=100010;

    for (register int i=1;i<=n;i++)

    {

        int x; x=read();

        rk[x]=++up; rkto[up]=x; insert(x);

    }

    for (register int i=1;i<=m;i++)

    {

        scanf("%s",s+1);

        if (s[1]=='Q') {int kk; kk=read(); printf("%d\n",findth(kk));}

        else if (s[1]=='T')

        {

            int xx; xx=read(); del(xx);

            rk[xx]=--down; rkto[down]=xx; insert(xx);

        }

        else if (s[1]=='B')

        {

            int xx; xx=read(); del(xx);

            rk[xx]=++up; rkto[up]=xx; insert(xx);

        }

        else if (s[1]=='A') {int kk; kk=read(); printf("%d\n",find(kk));}

        else if (s[1]=='I')

        {

            int ss,tt; ss=read(); tt=read();

            if (!tt) continue;

            int rk1=find(ss)+1,rk2=rk1+tt;

            int p1=ss,p2=findth(rk2);

            int nn1=rk[p1],nn2=rk[p2];

            del(p1); del(p2);

            rk[p1]=nn2; rkto[nn2]=p1;

            rk[p2]=nn1; rkto[nn1]=p2;

            insert(p1); insert(p2);

        }

    }

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值