BZOJ1861 [Zjoi2006]Book 书架 [平衡树]

书 架 书架

题目描述见链接 .


最 初 想 法 \color{grey}{最初想法}

使用 S p l a y Splay Splay维护


Input: 依次插入节点, 不断 初始插入 到上个节点的右子树中


Top : 将权值为 S S S的点 删去 , 再插入作为到 S p l a y Splay Splay的最左边儿子的左儿子


Bottom : 将权值为 S S S的点 删去 , 在插入作为 S p l a y Splay Splay的最右边儿子的右儿子


Insert : 将权值为 S S S的点 删去 , 设删去的点等级为 x x x, 将等级为 x + T − 1 x+T-1 x+T1的点 S p l a y Splay Splay到根节点, 把 S S S插入之间 根节点 (不要在意语序…)


Ask : 直接将 S S S节点 S p l a y Splay Splay到根节点, 输出左子树大小即可


Query : 查询第 S S S大的元素


初始插入 : 不断将当前节点插入到 上个插入节点 的右子树即可, 不要忘记Splay到根节点
删去 : 直接前缀后缀删除法即可
插入之间 : 将该节点的未来 p a r par par的右儿子置为该节点, 该节点的右儿子置为 p a r par par原来的右儿子


正 解 部 分 \color{red}{正解部分}

初始化序列 时不断将第 i i i 个元素插入作为第 i − 1 i-1 i1 个元素的右子树 .

  • T o p Top Top 操作: 直接将 i i i 元素旋转到根节点, 将其左子树变为 i i i后继 的左儿子 .
  • B o t t o m Bottom Bottom 操作: 直接将 i i i 元素旋转到根节点, 将其右子树变为 i i i前驱 的右儿子 .
  • I n s e r t Insert Insert 操作: 直接将 i i i 元素 与其 前驱/后继 的信息 进行交换即可 .
  • A s k Ask Ask 操作: 直接将 i i i 旋转到根, 输出其左子树大小即可 .
  • Q u e r y Query Query 操作: 查询第 K K K 大即可 .

实 现 部 分 \color{red}{实现部分}

  • 注意 r o t a t e rotate rotate s i z e size size 的赋值顺序 .
  • 交换时交换的是位置, 不是值, 只要将相关映射和对应位置上的值交换即可 .
#include<bits/stdc++.h>
#define reg register

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 80005;

int N;
int M;
int Mp[maxn];

char Smp[10];

namespace BBT{

        int rot;
        int node_cnt;

        struct Node{ int v, fa, son[2], size; } T[maxn];

        bool chk(int x){ return T[T[x].fa].son[0] != x; }

        void rotate(int x){
                int y = T[x].fa, z = T[y].fa;
                int dir = chk(x), sn = T[x].son[dir^1];
                if(y == rot) rot = x;
                else T[z].son[chk(y)] = x; T[x].fa = z;
                T[y].son[dir] = sn, T[sn].fa = y;
                T[x].son[dir^1] = y, T[y].fa = x; 
                T[y].size = T[T[y].son[0]].size + T[T[y].son[1]].size + 1;
                T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size + 1;
        }

        void Splay(int x, int aim=0){
                while(T[x].fa != aim){
                        int y = T[x].fa, z = T[y].fa;
                        if(z != aim){
                                if(chk(x) == chk(y)) rotate(y);
                                else rotate(x);
                        }
                        rotate(x);
                }
        }
        
        int Kth(int k, int aim){
                int ls = T[k].son[0];
                if(T[ls].size + 1 == aim) return k;
                else if(T[ls].size >= aim) return Kth(ls, aim);
                return Kth(T[k].son[1], aim - T[ls].size - 1);
        }

        void Add_node(int x){
                Mp[x] = ++ node_cnt, T[node_cnt] = (Node){ x, 0, {0,0}, 1 };
                if(node_cnt > 1){
                        T[node_cnt-1].son[1] = node_cnt, T[node_cnt].fa = node_cnt - 1;
                        Splay(node_cnt);
                }
        }

        void Top(int k){
                Splay(k);

                if(!T[k].son[0]) return ;
                else if(!T[k].son[1]){ T[k].son[1] = T[k].son[0], T[k].son[0] = 0; return ; } 

                int ls = T[k].son[0];
                int y = Kth(rot, T[ls].size+2);
                T[y].son[0] = ls, T[ls].fa = y, T[k].son[0] = 0;
                Splay(y);
        }

        void Bottom(int k){
                Splay(k);
                if(!T[k].son[1]) return ;
                else if(!T[k].son[0]){ T[k].son[0] = T[k].son[1], T[k].son[1] = 0; return ; }
                int ls = T[k].son[0], rs = T[k].son[1];
                int y = Kth(rot, T[ls].size);
                T[y].son[1] = rs, T[rs].fa = y, T[k].son[1] = 0;
                Splay(y);
        }

        void Insert(int k, int opt){
                if(!opt) return ;
                Splay(k);
                int rk = T[T[k].son[0]].size + 1, y = Kth(rot, rk + opt);
                std::swap(Mp[T[k].v], Mp[T[y].v]);
                std::swap(T[k].v, T[y].v);

        }

        void Ask(int k){ Splay(k); printf("%d\n", T[T[k].son[0]].size); }

        void Query(int rk){ int y = Kth(rot, rk); printf("%d\n", T[y].v); }

} 

void Work(){
        scanf("%s", Smp);
        int x = read();
        if(Smp[0] == 'T') BBT::Top(Mp[x]);
        else if(Smp[0] == 'B') BBT::Bottom(Mp[x]);
        else if(Smp[0] == 'I') BBT::Insert(Mp[x], read());
        else if(Smp[0] == 'A') BBT::Ask(Mp[x]);
        else BBT::Query(x);
}

int main(){
        N = read(), M = read();
        BBT::rot = 1;
        for(reg int i = 1; i <= N; i ++) BBT::Add_node(read());
        while(M --) Work();
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值