[BZOJ 1861] 书架

Link:

BZOJ 1861 传送门

Solution:

一道平衡树裸题调了两小时真是**

操作都比较常规:

1、$Top,Bottom$操作

先将$x$转到根节点,分情况讨论将其左/右子树合并到另一边去

2、$Insert$操作

其实完全没有必要先删除再插入,直接将$x$与其前驱/后继的信息交换就好了

 

Tip:

1、总感觉自己几个量分不清:点的序号,点的权值,点的排名(即在序列中的次序)

此题中$pos[x]$由权值指向序号,因此只有交换节点时改变,其他时候不用更新

2、一般要对节点进行操作都要将其先旋转到根节点,感觉自己老忘……

3、如果对交换前的值有调用,一定要将原值先存下来!

Code:

#include <bits/stdc++.h>

using namespace std;
const int MAXN=1e5+10;
char s[20];int x,y;
int n,m,rt,dat[MAXN],ch[MAXN][2],f[MAXN],sz[MAXN],pos[MAXN],val[MAXN],tot=0;

void pushup(int x)
{sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}

void Build(int l,int r,int anc)
{
    if(l>r) return;
    int mid=(l+r)/2;
    if(mid<anc) ch[anc][0]=mid;
    else ch[anc][1]=mid;
    f[mid]=anc;sz[mid]=1;
    val[mid]=dat[mid];pos[dat[mid]]=mid;
    
    Build(l,mid-1,mid);Build(mid+1,r,mid);
    pushup(mid);
}

void Rotate(int x)
{
    int y=f[x],z=f[y],k=(ch[y][1]==x);
    ch[z][ch[z][1]==y]=x;f[x]=z;
    ch[y][k]=ch[x][k^1];f[ch[x][k^1]]=y;
    ch[x][k^1]=y;f[y]=x;
    pushup(x);pushup(y);
}

void Splay(int x,int up)
{
    while(f[x]!=up)
    {
        int y=f[x],z=f[y];
        if(z!=up) (ch[y][1]==x)^(ch[z][1]==y)?Rotate(x):Rotate(y);
        Rotate(x);
    }
    if(!up) rt=x;
}

int Kth(int x)
{
    int k=rt;
    while(true)
    {
        if(sz[ch[k][0]]+1==x) return k;
        else if(sz[ch[k][0]]>=x) k=ch[k][0];
        else x-=sz[ch[k][0]]+1,k=ch[k][1];
    }
}

void Top(int x)
{
    x=pos[x];Splay(x,0);
    if(!ch[x][0]) return;
    if(!ch[x][1]){ch[x][1]=ch[x][0];ch[x][0]=0;return;}
    int y=Kth(sz[ch[x][0]]+2);
    ch[y][0]=ch[x][0];f[ch[x][0]]=y;ch[x][0]=0;
    Splay(y,0);
}

void Bottom(int x)
{
    x=pos[x];Splay(x,0);
    if(!ch[x][1]) return;
    if(!ch[x][0]){ch[x][0]=ch[x][1];ch[x][1]=0;return;}
    int y=Kth(sz[ch[x][0]]);
    ch[y][1]=ch[x][1];f[ch[x][1]]=y;ch[x][1]=0;
    Splay(y,0);
}

void Move(int x,int flag)
{
    if(!flag) return;
    Splay(pos[x],0);//一定要先Splay 
    int y=Kth(flag==1?sz[ch[pos[x]][0]]+2:sz[ch[pos[x]][0]]);
    int t=pos[x];//一定要先保留,否则再调用pos[x]时其值就变了 
    swap(pos[x],pos[val[y]]);
    swap(val[t],val[y]);
}

int Ask(int x)
{Splay(pos[x],0);return sz[ch[rt][0]];}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&dat[i]);
    rt=(n+1)/2;Build(1,n,rt);f[rt]=0;
    
    for(int i=1;i<=m;i++)
    {
        scanf("%s%d",s,&x);
        if(s[0]=='T') Top(x);
        else if(s[0]=='B') Bottom(x);
        else if(s[0]=='I') scanf("%d",&y),Move(x,y);
        else if(s[0]=='A') printf("%d\n",Ask(x));
        else if(s[0]=='Q') printf("%d\n",val[Kth(x)]);
    }
    return 0;
}

 

posted @ 2018-07-20 22:32  NewErA  阅读(177)  评论(0编辑  收藏  举报