首页 > 代码库 > POJ3468--A Simple Problem with Integers(Splay Tree)

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;}

 

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