POJ3468--A Simple Problem with Integers(Splay Tree)

虽然有点难,但是这套题都挂了一个月了啊喂……

网上模板好多……最后还是抄了kuangbin聚聚的,毕竟好多模板都是抄他的,比较习惯……

POJ 3468

题意:给n个数,两种操作,区间整体加一个数,或者区间求和。

题解:把区间的前一个数挪到根,区间后一个数挪到根的右子树,根的右子树的左子树就是要处理的区间。。。

SplayTree是一个二叉排序树,它所保存的顺序是数字的编号,所以无论怎样旋转,编号的顺序都不会变。。。

在首尾各插入一个结点,这样求整个区间的时候也可以找到前一个数和后一个数。。。

照了别人的博客写了两遍,自己又裸敲一遍,还是错了好多细节,不过大概理解了。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 100010;
int sz[N], ch[N][2], pre[N];
int a[N];
ll sum[N], add[N], key[N];
int root, tot;

void new_node(int &o, int fa, int k) {
    o = ++tot;
    sz[o] = 1;
    ch[o][0] = ch[o][1] = 0;
    pre[o] = fa;
    sum[o] = key[o] = k;
    add[o] = 0;
}

void push_up(int o) {
    sum[o] = sum[ch[o][0]] + sum[ch[o][1]] + key[o];
    sz[o] = sz[ch[o][0]] + sz[ch[o][1]] + 1; // +1 !!
}

void update(int o, int v) {
    if (!o) return ;
    add[o] += v;
    key[o] += v;
    sum[o] += (ll)sz[o]*v;
}

void push_down(int o) {
    if (add[o]) {
        update(ch[o][1], add[o]);
        update(ch[o][0], add[o]);
        add[o] = 0;
    }
}

void build(int &o, int l, int r, int fa) {
    if (l > r) return;
    int mid = (l+r) >> 1;
    new_node(o, fa, a[mid]);
    build(ch[o][0], l, mid-1, o);
    build(ch[o][1], mid+1, r, o);
    push_up(o);
}

void init(int n) {
    root = tot = 0;
    sz[0] = ch[0][0] = ch[0][1] = pre[0] = 0;
    sum[0] = add[0] = key[0] = 0;
    new_node(root, 0, -1);
    new_node(ch[root][1], root, -1);
    build(ch[ch[root][1]][0], 1, n, ch[root][1]);
    push_up(ch[root][1]);
    push_up(root);
}

void rotate(int o, int d) { // 0:left  1:right
    int fa = pre[o];
    push_down(fa);
    push_down(o);
    ch[fa][!d] = ch[o][d];
    pre[ch[o][d]] = fa;
    if (pre[fa]) ch[pre[fa]][ch[pre[fa]][1]==fa] = o;
    pre[o] = pre[fa];
    ch[o][d] = fa;
    pre[fa] = o;
    push_up(fa);
}

void splay(int o, int goal) {
    push_down(o);
    while (pre[o] != goal) {
        if (pre[pre[o]] == goal) {
            rotate(o, ch[pre[o]][0] == o);
        } else {
            int fa = pre[o];
            int d = (ch[pre[fa]][0] == fa);
            if (ch[fa][d] == o) {
                rotate(o, !d);
                rotate(o, d);
            } else {
                rotate(fa, d);
                rotate(o, d);
            }
        }
    }
    push_up(o);
    if (goal == 0) root = o;
}

int get_kth(int o, int k) {
    push_down(o); //!!
    int t = sz[ch[o][0]] + 1;
    if (t == k) return o;
    if (t > k) return get_kth(ch[o][0], k);
    return get_kth(ch[o][1], k-t);
}

ll query(int l, int r) {
    splay(get_kth(root, l), 0);
    splay(get_kth(root, r+2), root);
    return sum[ ch[ch[root][1]][0] ];
}

void Add(int l, int r, int v) {
    splay(get_kth(root, l), 0);
    splay(get_kth(root, r+2), root);
    update(ch[ch[root][1]][0], v);
    push_up(ch[root][1]);
    push_up(root);
}

int main() {
    //freopen("in.txt", "r", stdin);
    int n, q;
    while (~scanf("%d%d", &n, &q) && n) {
        for (int i = 1; i <= n; ++i) scanf("%d", a+i);
        init(n);
        char op[2];
        int x, y, z;
        while (q--) {
            scanf("%s%d%d", op, &x, &y);
            if (*op == 'Q') {
                printf("%lld\n", query(x, y));
            } else {
                scanf("%d", &z);
                Add(x, y, z);
            }
        }
    }
    return 0;
}

 

posted @ 2016-09-01 16:21  我不吃饼干呀  阅读(280)  评论(0编辑  收藏  举报