3224: Tyvj 1728 普通平衡树 伸展树

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3224

题解:灵活运用,像这种不对区间操作的,相同的数放到一块就可以了

#include <bits/stdc++.h>
using namespace std;
#define INF 2e9 + 10
const int N = 1e5 + 10;
struct Splaytree {
    int nex[N][2]; 
    int f[N];
    int sz[N];  // 子树节点个数 
    int val[N]; // 当前节点的值
    int cnt[N]; // 当前节点个数 
    int root;
    int tot;
    void init() {
        root = 0;
        tot = 0;
        f[0] = sz[0] = nex[0][0] = nex[0][1] = 0;
        cnt[0] = 0;
    }
    void newnode(int rt, int v, int fa) {
        f[rt] = fa;
        sz[rt] = 1;
        val[rt] = v;
        cnt[rt] = 1;
        nex[rt][0] = nex[rt][1] = 0;
    } 
    void delnode(int rt) {
        f[rt] = sz[rt] = val[rt] = cnt[rt] = 0;
        nex[rt][0] = nex[rt][1] = 0;
    }
    void pushup(int rt) {
        if(!rt) return;
        sz[rt] = cnt[rt];
        if(nex[rt][0]) sz[rt] += sz[nex[rt][0]];
        if(nex[rt][1]) sz[rt] += sz[nex[rt][1]];
    }
    void build(int &rt, int l, int r, int fa) {
        if(l > r) return;
        int mid = (l + r) >> 1;
        rt = mid;
        newnode(rt, val[rt], fa);
        cnt[rt] = 1;
        build(nex[rt][0], l, mid - 1, rt);
        build(nex[rt][1], mid + 1, r, rt);
    }

    void rotate(int x, int k) { // 0:左旋 1:右旋  
        int y = f[x];
        int z = f[y];

        nex[y][!k] = nex[x][k];
        if(nex[x][k]) f[nex[x][k]] = y;
        f[x] = z;
        if(z) nex[z][nex[z][1] == y] = x;
        f[y] = x;
        nex[x][k] = y;
        pushup(y);
        pushup(x);
    }
    void splay(int x, int goal) { // x 旋转到 goal下面 
        while(f[x] != goal) {
            if(f[f[x]] == goal) rotate(x, nex[f[x]][0] == x);
            else {
                int y = f[x], z = f[y];
                int K = (nex[z][0] == y);
                if(nex[y][K] == x) rotate(x, !K), rotate(x, K);
                else rotate(y, K), rotate(x, K);
            }
        } 
        pushup(x);
        if(goal == 0) root = x;
    }
    int search(int rt, int x) { // 查询权值为x的节点 
        if(nex[rt][0] && val[rt] > x) return search(nex[rt][0], x);
        else if(nex[rt][1] && val[rt] < x) return search(nex[rt][1], x);
        else return rt;
    }
    int extreme(int rt, int k) { // 子树最值节点 0小 1大 
        while(nex[rt][k]) rt = nex[rt][k];
        splay(rt, 0);
        return rt;
    } 
    int getkth(int rt, int k) {
        if(sz[nex[rt][0]] < k && k <= sz[nex[rt][0]] + cnt[rt]) return rt;
        else if(sz[nex[rt][0]] >= k) return getkth(nex[rt][0], k);
        else return getkth(nex[rt][1], k - sz[nex[rt][0]] - cnt[rt]);
    } 
    int prec(int x) { // 前驱 
        int k = search(root, x);
        splay(k, 0);
        if(val[k] < x) return k;
        return extreme(nex[k][0], 1); 
    }
    int sufc(int x) { // 后继 
        int k = search(root, x);
        splay(k, 0);
        if(val[k] > x) return k;
        return extreme(nex[k][1], 0); 
    }
    void insert(int x) { // 插入 
        int y = search(root, x);
        if(val[y] == x) {
            cnt[y]++;
            sz[y]++;
            for(int k = y; k; k = f[k]) pushup(k);
            splay(y, 0);
        } else {
            int p = prec(x);
            int s = sufc(x);
            splay(p, 0);
            splay(s, p);
            newnode(++tot, x, nex[root][1]);
            nex[nex[root][1]][0] = tot;
            for(int k = nex[root][1]; k; k = f[k]) pushup(k);
        }
    }
    void delete_(int x) { // 删除 
        int y = search(root, x);
        if(val[y] != x) return;
        if(cnt[y] > 1) {
            cnt[y]--;
            sz[y]--;
            for(int k = y; k; k = f[k]) pushup(k);
        }  else if(nex[y][0] == 0 || nex[y][1] == 0) {
            int z = f[y];
            nex[z][nex[z][1] == y] = nex[y][nex[y][0] == 0];
            f[nex[y][nex[y][0] == 0]] = z;
            delnode(y);
            for(int k = z; k; k = f[k]) pushup(k);
        } else {
            int p = prec(x);
            int s = sufc(x);
            splay(p, 0);
            splay(s, p);
            nex[nex[root][1]][0] = 0;
            delnode(nex[nex[root][1]][0]);
            for(int k = s; k; k = f[k]) pushup(k);
        }
    }
    int getrank(int x) { // 某权值的排名 
        int k = search(root, x);
        splay(k, 0);
        return sz[nex[k][0]] + 1;
    }

}p;
int n;
int main() {
    scanf("%d", &n);
    p.init();
    p.val[1] = -INF;
    p.val[2] = INF;
    p.tot = 2;
    p.build(p.root, 1, 2, 0);
    p.pushup(p.root);
    int op, x;
    for(int i = 1; i <= n; i++) {
        scanf("%d %d", &op, &x);
        if(op == 1) p.insert(x);
        else if(op == 2) p.delete_(x);
        else if(op == 3) printf("%d\n", p.getrank(x) - 1);
        else if(op == 4) printf("%d\n", p.val[p.getkth(p.root, x + 1)]);
        else if(op == 5) printf("%d\n", p.val[p.prec(x)]);
        else printf("%d\n", p.val[p.sufc(x)]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值