【HDU 3487】Play with Chain(Splay)

本文详细介绍了伸展树(Splay Tree)的基本操作,包括删除指定区间及旋转区间的方法。通过C++实现提供了具体的伸展树旋转、翻转、切割等操作的代码示例,有助于读者深入理解伸展树的运作机制。

Splay的基础操作。

1、删除某一个区间,然后从某个位置插入,可以将其旋转到关键树上去然后删掉就行了

2、旋转某个区间。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define keytree (ch[ ch[root][1] ][0])
using namespace std;
const int SIZEN = 300005;
struct SplayTree{
    int ch[SIZEN][2];
    int pre[SIZEN];
    int sz[SIZEN];
    int top,root,cnt,n;

    inline void pushup(int x){
        sz[x] = sz[ ch[x][0] ] + sz[ ch[x][1] ] + 1;
    }
    inline void change(int x){
        swap(ch[x][0],ch[x][1]);
    }
    inline void pushdown(int x){
        if(lazy[x]){
            lazy[ ch[x][0] ] ^= 1;
            lazy[ ch[x][1] ] ^= 1;
            change(ch[x][0]);
            change(ch[x][1]);
            lazy[x] = 0;
        }
    }
    void Travel(int x){
        pushdown(x);
        if(ch[x][0]) Travel(ch[x][0]);
        printf("node:%d lson:%d rson:%d pre:%d val:%d sz:%d\n",x,ch[x][0],ch[x][1],pre[x],val[x],sz[x]);
        if(ch[x][1]) Travel(ch[x][1]);
    }
    void debug(){
        printf("root:%d\n",root);
        Travel(root);
    }
    inline void Rotate(int x,int f) {
        int y = pre[x];
        pushdown(y);
        pushdown(x);
        ch[y][!f] = ch[x][f];
        pre[ ch[x][f] ] = y;
        pre[x] = pre[y];
        if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] = x;
        ch[x][f] = y;
        pre[y] = x;
        pushup(y);
    }
    inline void Splay(int x,int goal) {
        pushdown(x);
        while(pre[x] != goal) {
            if(pre[pre[x]] == goal) {
                Rotate(x , ch[pre[x]][0] == x);
            } else {
                int y = pre[x] , z = pre[y];
                pushdown(z);
                pushdown(y);
                pushdown(x);
                int f = (ch[z][0] == y);
                if(ch[y][f] == x) {
                    Rotate(x , !f) , Rotate(x , f);
                } else {
                    Rotate(y , f) , Rotate(x , f);
                }
            }
        }
        pushup(x);
        if(goal == 0) root = x;
    }
    void Rotateto(int k,int goal) {
        int x = root;
        pushdown(x);
        while(sz[ ch[x][0] ] != k) {
            if(k < sz[ ch[x][0] ]) {
                x = ch[x][0];
            } else {
                k -= (sz[ ch[x][0] ] + 1);
                x = ch[x][1];
            }
            pushdown(x);
        }
        Splay(x,goal);
    }
    int Newnode(int x){
        ch[x][0] = ch[x][1] = 0;
        pre[x] = lazy[x] = 0;
        sz[x] = 1;
        val[x] = x;
        return x;
    }
    inline void build(int &x,int l,int r,int f){
        if(l > r) return;
        int mid = (l + r) >> 1;
        x = Newnode(mid);
        build(ch[x][0],l,mid - 1,x);
        build(ch[x][1],mid + 1,r,x);
        pre[x] = f;
        pushup(x);
    }
    inline void init(){
        ch[0][0] = ch[0][1] = pre[0] = 0;
        sz[0] = lazy[0] = val[0] = 0;
        root = top = cnt = 0;
        root = Newnode(n + 1);
        ch[root][1] = Newnode(n + 2);
        pre[ ch[root][1] ] = root;
        sz[root] = 2;
        build(keytree,1,n,ch[root][1]);
        pushup(ch[root][1]);
        pushup(root);
    }
    inline void flip(){
        int l,r;
        scanf("%d%d",&l,&r);
        Rotateto(l - 1,0);
        //debug();
        Rotateto(r + 1,root);
        lazy[keytree] ^= 1;
        change(keytree);
    }
    inline void cut(){
        int l,r,next;
        scanf("%d%d%d",&l,&r,&next);
        Rotateto(l - 1,0);
        Rotateto(r + 1,root);
        cnt = 0;
        int tmp = keytree;
        ch[ ch[root][1] ][0] = 0;
        pushup(ch[root][1]);
        Rotateto(next,0);
        Rotateto(next + 1,root);
        keytree = tmp;
        pre[tmp] = ch[root][1];
        pushup(ch[root][1]);
    }
    void output(int x){
        pushdown(x);
        if(ch[x][0]) output(ch[x][0]);
        if(val[x] <= n){
            cnt++;
            printf("%d",val[x]);
            printf(cnt == n?"\n":" ");
        }
        if(ch[x][1]) output(ch[x][1]);
    }

    int lazy[SIZEN];
    int val[SIZEN];
};
SplayTree spt;
void solve(int n,int m){
    char op[10];
    spt.n = n;
    spt.init();
    while(m--){
        scanf("%s",op);
        if(op[0] == 'C') spt.cut();
        else if(op[0] == 'F') spt.flip();
        spt.cnt = 0;
    }
    spt.output(spt.root);
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n < 0 && m < 0) break;
        solve(n,m);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值