zoukankan      html  css  js  c++  java
  • 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);
            }
        }
    }
  • 相关阅读:
    ADB 多设备中指定设备的启动
    vuex 绑定表单,多个输入框的解决办法
    vue 自动触发点击事件
    js 打印dom的所有属性
    邮件分享
    table表格 td设置固定宽度
    Echarts--Y坐标标题显示不全
    ExtJS5.0 菜鸟的第一天
    字体设置
    短信验证码+倒计时
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/11311435.html
Copyright © 2011-2022 走看看