非旋转 Treap 学习笔记(二)

来源:互联网 发布:js obj动态添加key 编辑:程序博客网 时间:2024/05/29 03:44

非旋转 Treap 学习笔记(一) 没有涉及一些区间的操作只是最基本的 Treap 操作,这篇才是非旋 Treap 真正优秀的地方。

要注意涉及区间操作时插入就是按照位置插入的,而不是按照权值的排名插入了。

Luogu P3391 【模板】文艺平衡树(Splay)

插入的时候分离前 pos - 1 个。
比如 1 2 3 4 5,在第 3 个位置插入一个 8,变成 1 2 8 3 4 5
把前面 1 2 分裂出来,后面 3 4 5 分裂出来

1 ~ n 分为 1 ~ (l - 1), l ~ r, (r + 1) ~ n 找到要翻转的区间 l ~ r 并标记。
在 pushDown 时翻转,就是将标记的节点 v 的左右子树交换,并不断将标记下传。
每次在 split 和 merge 的时候记得 pushDown。

最后 dfs 中序遍历一次求出最终翻转后的数列。

#include <bits/stdc++.h>using namespace std;const int N = 1e5 + 5;struct Treap {    struct Node {        Node *lc, *rc;        int x, size, key;        bool rev;        Node(int x) : lc(NULL), rc(NULL), x(x), size(1), key(rand() * rand() * rand()), rev(false) {}        inline void reverse() { rev ^= 1; }        inline void pushDown() {            if (rev) {                swap(lc, rc);                if (lc) lc->reverse();                if (rc) rc->reverse();                rev = false;            }        }        inline void maintain() { size = (lc ? lc->size : 0) + (rc ? rc->size : 0) + 1; }        inline int lSize() { return lc ? lc->size : 0; }     } *root;    /*int lowerCount(int x) {        Node *v = root;        int res = 0;        while (v) {            v->pushDown();            if (x <= v->x) v = v->lc;            else res += v->lSize() + 1, v = v->rc;        }        return res;    }    int upperCount(int x) {        Node *v = root;        int res = 0;        while (v) {            v->pushDown();            if (x < v->x) v = v->lc;            else res += v->lSize() + 1, v = v->rc;        }        return res;    }*/     inline void split(Node *v, int k, Node *&l, Node *&r) {        if(!v) { l = r = NULL; return ; }        v->pushDown();        int s = v->lSize();        if(k <= s) {            split(v->lc, k, l, r);            v->lc = r;            r = v;        } else {            split(v->rc, k - s - 1, l, r);            v->rc = l;            l = v;        }        v->maintain();    }    Node *merge(Node *a, Node *b) {        if (!a && !b) return NULL;        if (!a) { b->maintain(); return b; } //        if (!b) { a->maintain(): return a; }        a->pushDown();        b->pushDown();        if (a->key > b->key) {            a->rc = merge(a->rc, b);            a->maintain();            return a;        } else {            b->lc = merge(a, b->lc);            b->maintain();            return b;        }    }    inline void insert(int pos, int x) {        Node *pred, *tmp;        split(root, pos - 1, pred, tmp);        Node *v = new Node(x);        root = merge(pred, merge(v, tmp));    }    bool reverse(int l, int r) {        Node *pred, *tmp;        split(root, l - 1, pred, tmp);        Node *target, *succ;        split(tmp, r - l + 1, target, succ);        target->reverse();        root = merge(pred, merge(target, succ));    }    void dfs(Node *v, int *&p) {        if (!v) return ;        v->pushDown();        dfs(v->lc, p);        *p ++ = v->x;        dfs(v->rc, p);    }    void fetch(int a[]) { // p 是引用,会在整个递归过程中改变        int *p = &a[1];        dfs(root, p);    }} treap;int main() {    int n, m;    scanf("%d%d", &n, &m);    for (int i = 1; i <= n; i ++) treap.insert(i, i);    for (int i = 1; i <= m; i ++) {        int l, r;        scanf("%d%d", &l, &r);        treap.reverse(l, r);    }    static int a[N];    treap.fetch(a); // 中序遍历一遍    for (int i = 1; i <= n; i ++) printf("%d%c", a[i], " \n"[i ==n]);    return 0;}
原创粉丝点击