Luogu P2596 [ZJOI2006]书架

平衡树(splay)

先以书堆从上到下的下标为权值建立平衡树,对于splay中每个节点记录书的编号

那么现在得到的是有序的书堆

在五个操作之中1,2,3操作较难进行处理

先考虑3操作

当$t=0$时,位置不动,不需要进行操作

当$t=-1$时,可以发现这本书需要插入的位置,就是这个这本书编号对应平衡树中的节点的前驱

那么将前驱的信息与这个节点的信息进行交换即可

同理,当$t=1$时,找出后继,进行交换信息即可

那么考虑1,2操作

对于置顶还是置底,都是将这个节点的权值设为最大或最小

那么记录当前平衡树中权值的最大值和最小值

对于操作的书,先删去其在平衡树中的节点,然后插入权值为最大值+1或最小值-1的节点

并在此节点记录信息即可

#include <bits/stdc++.h>
#define inf (int)1e9
using namespace std;
const int MAXN=80010;
int n,root,t,MAX,MIN;
int m;
int wh[MAXN];
struct node
{
    int sf,son[2],si,va,fa;
    int id;
}sh[MAXN*4];
int newcode()
{
    ++t;
    return t;
}
void pushup(int x)
{
    sh[x].si=1+sh[sh[x].son[0]].si+sh[sh[x].son[1]].si;
}
void connect(int x,int y,int s)
{
    sh[y].son[s]=x;
    sh[x].sf=s;
    sh[x].fa=y;
}
void clear()
{
    sh[0].fa=sh[0].sf=sh[0].si=sh[0].va=0;
    memset(sh[0].son,0,sizeof(sh[0].son));
}
void rotate(int x)
{
    int sf,fa,y,z,s;
    s=sh[x].sf;
    z=sh[x].son[sh[x].sf^1];
    sf=sh[sh[x].fa].sf;
    fa=sh[sh[x].fa].fa;
    y=sh[x].fa;
    connect(x,fa,sf);
    connect(y,x,s^1);
    connect(z,y,s);
    clear();
    pushup(y);
    pushup(x);
}
void splay(int x,int y)//splay基本操作
{
    while (sh[x].fa!=y)
    {
        if (sh[sh[x].fa].fa==y)
          rotate(x);
        else
        if (sh[sh[x].fa].sf==sh[x].sf)
        {
            rotate(sh[x].fa);
            rotate(x);
        }
        else
        {
            rotate(x);
            rotate(x);
        }
    }
    if (y==0)
      root=x;
}
void insert(int v,int who)//插入
{
    if (root==0)
    {
        sh[newcode()].va=v;
        sh[t].id=who;
        wh[who]=t;
        sh[t].si=1;
        root=t;
        return;
    }
    int cur;
    cur=root;
    while (sh[cur].son[v>sh[cur].va]!=0 && sh[cur].va!=v)
      cur=sh[cur].son[v>sh[cur].va];
    if (v>sh[cur].va)
      connect(newcode(),cur,1);
    else
      connect(newcode(),cur,0);
    sh[t].va=v;
    sh[t].id=who;
    wh[who]=t;
    sh[t].si=1;
    pushup(cur);
    splay(t,0);
}
void find(int v)
{
    int cur;
    cur=root;
    while (sh[cur].son[v>sh[cur].va]!=0 && sh[cur].va!=v)
      cur=sh[cur].son[v>sh[cur].va];
    splay(cur,0);
}
int per(int v)
{
    find(v);
    int cur;
    if (sh[root].va<v)
      return root;
    cur=sh[root].son[0];
    while (sh[cur].son[1]!=0)
      cur=sh[cur].son[1];
    return cur;
}
int succ(int v)
{
    find(v);
    int cur;
    if (sh[root].va>v)
      return root;
    cur=sh[root].son[1];
    while (sh[cur].son[0]!=0)
      cur=sh[cur].son[0];
    return cur;
}
void del(int v)
{
    int p,s;
    p=per(v);
    s=succ(v);
    splay(p,0);
    splay(s,p);
    int cur;
    cur=sh[s].son[0];
    sh[s].son[0]=0;
    sh[cur].fa=0;
    pushup(cur);
    pushup(s);
    pushup(p);
}
int rk(int x)
{
    find(x);
    return sh[sh[root].son[0]].si;
}
int kth(int x,int k)
{
    if (sh[sh[x].son[0]].si<k && k<=sh[sh[x].son[0]].si+1)
      return x;
    else
    if (k<=sh[sh[x].son[0]].si)
      return kth(sh[x].son[0],k);
    else
      return kth(sh[x].son[1],k-1-sh[sh[x].son[0]].si);
}
int main()
{
    root=0;
    insert(inf,0);
    insert(-inf,0);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        int a;
        scanf("%d",&a);
        insert(i,a);
    }
    MIN=0;
    MAX=n+1;
    while (m--)
    {
        char ch[20];
        int s;
        scanf("%s",ch);
        if (ch[0]=='T')
        {
            scanf("%d",&s);
            del(sh[wh[s]].va);
            insert(MIN,s);
            MIN--;
        }
        if (ch[0]=='B')
        {
            scanf("%d",&s);
            del(sh[wh[s]].va);
            insert(MAX,s);
            MAX++;
        }
        if (ch[0]=='I')
        {
            int t;
            scanf("%d%d",&s,&t);
            if (t==0)
              continue;
            int cur,who;
            if (t==-1)
              cur=per(sh[wh[s]].va);
            if (t==1)
              cur=succ(sh[wh[s]].va);
            who=sh[cur].id;
            swap(sh[cur].id,sh[wh[s]].id);
            swap(wh[who],wh[s]);//交换信息
        }
        if (ch[0]=='A')
        {
            scanf("%d",&s);
            printf("%d
",rk(sh[wh[s]].va)-1);//注意平衡树中还有inf和-inf的节点
        }
        if (ch[0]=='Q')
        {
            scanf("%d",&s);
            printf("%d
",sh[kth(root,s+1)].id);
        }
    }
}
原文地址:https://www.cnblogs.com/huangchenyan/p/11311435.html