牛客-Forsaken的数列(Treap)

题目传送门

sol:第一次看题还真信了是用线段树来做,但是没什么想法,看了题解发现是我不会的Treap,然后花了几天时间学习了一下并补掉题目

  • 无旋Treap
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int MAXN = 2e5 + 10;
    struct Treap {
        int ls, rs;
        int rand, size;
        LL sum, val, lazy;
    } node[MAXN];
    int root, tot;
    int add_node(int v) {
        int i = ++tot;
        node[i].ls = node[i].rs = 0;
        node[i].rand = rand();
        node[i].sum = node[i].val = v;
        node[i].lazy = 0;
        node[i].size = 1;
        return i;
    }
    void push_down(int rt) {
        int ls = node[rt].ls;
        int rs = node[rt].rs;
        if (ls != 0) {
            node[ls].lazy += node[rt].lazy;
            node[ls].val += node[rt].lazy;
            node[ls].sum += node[ls].size * node[rt].lazy;
        }
        if (rs != 0) {
            node[rs].lazy += node[rt].lazy;
            node[rs].val += node[rt].lazy;
            node[rs].sum += node[rs].size * node[rt].lazy;
        }
        node[rt].lazy = 0;
    }
    void push_up(int rt) {
        int ls = node[rt].ls;
        int rs = node[rt].rs;
        node[rt].size = node[ls].size + node[rs].size + 1;
        node[rt].sum = node[ls].sum + node[rs].sum + node[rt].val;
    }
    void split(int rt, int& a, int& b, int s) {
        if (rt == 0) {
            a = b = 0;
            return;
        }
        push_down(rt);
        int size = node[node[rt].ls].size;
        if (size < s) {
            a = rt;
            split(node[rt].rs, node[a].rs, b, s - size - 1);
        } else {
            b = rt;
            split(node[rt].ls, a, node[b].ls, s);
        }
        push_up(rt);
    }
    void merge(int& rt, int a, int b) {
        if (a == 0 || b == 0) {
            rt = a + b;
            return;
        }
        push_down(a);
        push_down(b);
        if (node[a].rand < node[b].rand) {
            rt = a;
            merge(node[rt].rs, node[a].rs, b);
        } else {
            rt = b;
            merge(node[rt].ls, a, node[b].ls);
        }
        push_up(rt);
    }
    void insert(int p, int v) {
        int x = 0, y = 0;
        split(root, x, y, p - 1);
        merge(root, x, add_node(v));
        merge(root, root, y);
    }
    void add(int l, int r, int v) {
        int x = 0, y = 0, z = 0;
        split(root, root, z, r);
        split(root, x, y, l - 1);
        node[y].lazy += v;
        node[y].val += v;
        node[y].sum += node[y].size * v;
        merge(root, x, y);
        merge(root, root, z);
    }
    LL query(int l, int r) {
        int x = 0, y = 0, z = 0;
        split(root, root, z, r);
        split(root, x, y, l - 1);
        LL sum = node[y].sum;
        merge(root, x, y);
        merge(root, root, z);
        return sum;
    }
    int main() {
        int n, q;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            int v; scanf("%d", &v);
            merge(root, root, add_node(v));
        }
        scanf("%d", &q);
        for (int i = 1; i <= q; i++) {
            int opt; scanf("%d", &opt);
            if (opt == 1) {
                int pos; scanf("%d", &pos);
                insert(pos, 0);
            } else if (opt == 2) {
                int l, r, v;
                scanf("%d%d%d", &l, &r, &v);
                add(l, r, v);
            } else {
                int l, r;
                scanf("%d%d", &l, &r);
                printf("%lld\n", query(l, r));
            }
        }
        return 0;
    }

    在前置知识都掌握的情况下Treap还是挺好懂的,而且之前感觉lazy标记挺乱的,看了这题之后感觉理清了

posted @ 2019-11-06 11:09  Angel&Demon  阅读(...)  评论(... 编辑 收藏