欢迎光临散文网 会员登陆 & 注册

161 普通平衡树 Splay

2023-05-04 23:45 作者:零-雪鸦  | 我要投稿

老师的代码有点瑕疵,这里我补充一下,但是这里的瑕疵是学算法才能感知到的,如果是新人的话就是需要一一对比,即用老师的代码做洛谷 P3369 【模板】普通平衡树 这题是AC的,但是做洛谷 P6136 【模板】普通平衡树(数据加强版)就不一定了,该题有点裸但是也不是太裸,他输入数据异或加密了。你用老师的板子做就不一定能过,因为 get_rank(这是我写的函数名) 老师的代码如果这个数不存在,就有点问题了。这是问题1,问题2就是.查前驱/后继 ,最后也要splay一次,不然复杂度保证不了,即就两个数据测试点TLE。记住注释也要看看

```C++

//P6136 【模板】普通平衡树(数据加强版)

#include <iostream>

using namespace std;

#define ls(x) tr[x].son[0]

#define rs(x) tr[x].son[1]

const int MAX_N = 1e5 + 5, MAX_M = 1e6 + 5;

const int MAX_SIZE = MAX_N + MAX_M;

const int  INF = (1 << 30) + 1;

struct Node {

    int son[2]; //左右儿子

    int parent; //父亲

    int val; //节点权值

    int cnt; //权值出现次数

    int siz; //子树大小

    void init(int parent_, int val_) {

        parent = parent_, val = val_;

        cnt = siz = 1;

    }

} tr[MAX_SIZE];

int root, idx; //根节点编号,节点个数

void pushup(int x) {//x 下标

    tr[x].siz = tr[ls(x)].siz + tr[rs(x)].siz + tr[x].cnt;

}

void rotate(int x) {//x 下标

    int y = tr[x].parent, z = tr[y].parent;

    int k = tr[y].son[1] == x;

    tr[z].son[tr[z].son[1] == y] = x;

    tr[x].parent = z;

    tr[y].son[k] = tr[x].son[k ^ 1];

    tr[tr[x].son[k ^ 1]].parent = y;

    tr[x].son[k ^ 1] = y;

    tr[y].parent = x;

    pushup(y), pushup(x);

}

void splay(int x, int k) {

    while (tr[x].parent != k) {

        int y = tr[x].parent, z = tr[y].parent;

        if (z != k) // 折转底,直转中

            (ls(y) == x)^(ls(z) == y) ? rotate(x) : rotate(y);

        rotate(x);

    }

    if (!k) root = x;

}

void insert(int v) { //插入数值v

    int x = root, p = 0;

    while (x && tr[x].val != v)

        p = x, x = tr[x].son[v > tr[x].val];

    if (x) tr[x].cnt++;

    else {

        x = ++idx;

        tr[p].son[v > tr[p].val] = x;

        tr[x].init(p, v);

    }

    splay(x, 0);

}

void find(int v) { //找到数值v并转到根

    int x = root;

    while (tr[x].son[v > tr[x].val] && v != tr[x].val)

        x = tr[x].son[v > tr[x].val];

    splay(x, 0);

}

int get_pre(int v) { //数值v前驱的编号

    find(v);

    int x = root;

    if (tr[x].val < v) return x;

    x = ls(x);

    while (rs(x)) x = rs(x);

    splay(x, 0);// 艹,少一句代码都TLE,#5样例TLE#6样例PASS

    return x;

}

int get_suc(int v) { //数值v后继的编号

    find(v);

    int x = root;

    if (tr[x].val > v) return x;

    x = rs(x);

    while (ls(x)) x = ls(x);

    splay(x, 0);// #5样例PASS#6样例TLE

    return x;

}

void del(int v) { //数值v删除

    int pre = get_pre(v);

    int suc = get_suc(v);

    splay(pre, 0), splay(suc, pre);

    int del = tr[suc].son[0];

    if (tr[del].cnt > 1)

        tr[del].cnt--, splay(del, 0);

    else

        tr[suc].son[0] = 0, splay(suc, 0);

}

int get_rank(int v) { //数值v排名

//    这里老师的代码有问题

//    find(v);

//    return tr[tr[root].son[0]].siz;

    insert(v);

    int res = tr[tr[root].son[0]].siz;

    del(v);

    return res;

}

int get_val_by_rank(int k) { //数值

    int x = root;

    while (1) {

        int y = ls(x);

        if (tr[y].siz + tr[x].cnt < k)

            k -= tr[y].siz + tr[x].cnt,

                 x = rs(x);

        else if (tr[y].siz >= k) x = y;

        else break;

    }

    splay(x, 0);

    return tr[x].val;

}

int main() {

    ios::sync_with_stdio(false);

    cin.tie(nullptr);

    insert(-INF);

    insert(INF); //哨兵

    int n, m;

    scanf("%d%d", &n, &m);

    int x;

    while (n--) {

        scanf("%d", &x);

        insert(x);

    }

    int op, res = 0, last = 0;

    while (m--) {

        scanf("%d%d", &op, &x);

        x ^= last;

        if (op == 1) insert(x);

        if (op == 2) del(x);

        if (op == 3) res ^= (last = get_rank(x))/*,cout << "加密后:3  " << x << endl*/;

        if (op == 4) res ^= (last = get_val_by_rank(x + 1))/*, cout << "加密后:4  " << x << endl*/;

        if (op == 5) res ^= (last = tr[get_pre(x)].val)/*, cout << "加密后:5  " << x << endl*/;

        if (op == 6) res ^= (last = tr[get_suc(x)].val)/*, cout << "加密后:6  " << x << endl*/;

    }

    cout << res << '\n';

    return 0;

}

```



161 普通平衡树 Splay的评论 (共 条)

分享到微博请遵守国家法律