BZOJ 1861 伸展树基本操作

本文介绍了一道关于Splay树的数据结构题目,通过实现关键函数进行节点操作和树的维护。文章详细展示了如何处理节点插入、删除及查询等操作,并提供了一段完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.lydsy.com/JudgeOnline/problem.php?id=1861

写好关键的三个函数后就是水水的模拟题,旋转来旋转去的操作,so easy

有几点值得注意:

1:取出Splay中某个节点,然后在插回去,这个节点的左右儿子要记得清空

2:每次更改关系后别忘了up上去

没了。。

#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
typedef long long lld;
#define L x->c[0]
#define R x->c[1]
#define KT root->c[1]->c[0]
const int maxn = 111111;
struct node {
    struct node *c[2], *fa;
    int id;
    int sz;
    int val;
    inline bool d() {
        return fa->c[0] == this;
    }
    inline void setc(int d, node *s) {
        c[d] = s;
        s->fa = this;
    }
    inline void up() {
        sz = c[0]->sz + c[1]->sz + 1;
    }
    inline void clear(node *null) {
        c[0] = c[1] = null;
        sz = 1;
    }
} NODE[2 * maxn], *null = &NODE[0] ;
int top;
node* ID[maxn];
struct SplayTree {
    node* root;
    void Rotate(node *x,int f) {
        node *y = x->fa;
        y->setc(!f,x->c[f]);
        x->fa = y->fa;
        if (y->fa != null)    y->fa->setc(!y->d(),x);
        x->setc(f,y);
        y->up();
    }
    void Splay(node *x, node *goal) {
        while (x->fa != goal) {
            if (x->fa->fa == goal)
                Rotate(x, x->d());
            else {
                int f = x->fa->d();
                x->d() == f ? Rotate(x->fa, f) : Rotate(x, !f);
                Rotate(x, f);
            }
        }
        x->up();
        if (goal == null) root = x;
    }
    void RTO(int k, node *goal) {
        if(k<1||k>root->sz) while(1);
        node *x = root;
        while (L->sz + 1 != k) {
            if(k < L->sz + 1) x = L;
            else {
                k -= L->sz + 1;
                x = R;
            }
        }
        Splay(x, goal);
    }
    void build(node* &x,int l,int r,node *fa) {
        if(l > r) return ;
        int m = l + r >>1;
        x = new_node(fa,num[m]);
        build(x->c[0],l,m-1,x);
        build(x->c[1],m+1,r,x);
        x->up();
    }
    node *new_node(node *fa, int v) {
        node *x = &NODE[++top];
        x->id = top;
        x->c[0] = x->c[1] = null;
        x->sz = 1;
        x->val = v;
        x->fa = fa;
        if(v!=-1) ID[v] = x;
        return x;
    }
    void init(int n) {
        for(int i = 1; i <= n; i++) scanf("%d",&num[i]);
        root = new_node(null,-1);
        build(root->c[1],1,n,root);
        root->up();
    }
    void Del_root() { // delete the root
        node* t = root;
        if (t->c[1] != null) {
            root = t->c[1];
            RTO(1, null);
            root->c[0] = t->c[0];
            if (root->c[0] != null)
                root->c[0]->fa = root;
        } else
            root = root->c[0];
        root->fa = null;
        if (root != null)
            root->up();
    }
    void Insert(int p,int v) {
        Splay(ID[p],null);
        int NC = root->c[0]->sz - 1;
        Del_root();
        ID[p]->clear(null);
        NC += v;
        RTO(NC+1,null);
        if(root->c[1] == null) {
            root->setc(1,ID[p]);
            root->up();
            return ;
        }
        RTO(NC+2,root);
        root->c[1]->setc(0,ID[p]); root->c[1]->up(); root->up();
    }
    void Bottom(int p) {
        Splay(ID[p],null);
        Del_root();
        ID[p]->clear(null);
        RTO(root->sz,null);
        root->setc(1,ID[p]); root->up();
    }
    void Top(int p) {
        Splay(ID[p],null);
        Del_root();
        ID[p]->clear(null);
        RTO(1,null);
        if(root->c[1] == null) {
            root->setc(1,ID[p]);
            return ;
        }
        RTO(2,root);
        root->c[1]->setc(0,ID[p]); root->c[1]->up(); root->up();
    }
    int Query(int p) {
        RTO(p+1,null);
        return root->val;
    }
    int Ask(int p) {
        Splay(ID[p],null);
        return root->c[0]->sz - 1;
    }
    void vist(node *x) {
        if (x != null) {
            printf("节点:%2d : 左儿子: %2d  右儿子:  %2d  sz: %2d val: %d\n",
                   x->id,x->c[0]->id,x->c[1]->id,x->sz,x->val);
            vist(x->c[0]);
            vist(x->c[1]);
        }
    }
    void debug() {
        puts("************");
        vist(root);
        puts("\n*****************");
    }
    int num[maxn];
} spt;
void prepare() {
    top = 0;
    null->id = 0;
    null->c[0] = null->c[1] = null->fa = NULL;
    null->sz = 0;
    null->val = 0;
}
int main() {
    char op[10];
    prepare();
    int n , m , p;
    scanf("%d%d",&n,&m);
    spt.init(n);
    while(m--) {
        scanf("%s",op);
        if(op[0] == 'Q') {
            scanf("%d",&p);
            printf("%d\n",spt.Query(p));
        } else if(op[0] == 'A') {
            scanf("%d",&p);
            printf("%d\n",spt.Ask(p));
        } else if(op[0] == 'B') {
            scanf("%d",&p);
            spt.Bottom(p);
        } else if(op[0] == 'T') {
            scanf("%d",&p);
            spt.Top(p);
        } else {
            int v;
            scanf("%d%d",&p,&v);
            spt.Insert(p,v);
        }
    }
    return 0;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值