/** * Splay 2657 ms * 刚入手 splay,这题做第三遍了。 先是线段树,然后树状数组,这次Splay * 写的挺顺,也1A。就是手有点抽筋 -__-。。 * 算入门题吧,不过树状数组那思路挺不错的。 * 这次就记splay,如果是用splay的话就大水了。 不过效率也低,比线段树还低。 * 思路的话,就是用splay维护个sum域,再打个lazy-tag * (这里用add表示以该顶点为树根的树表示的区间所需要添加的值。val表示该点的值) * 然后维护sum和add,每次push_down()就行了。。其实思想还是和线段树一样的 * * 还有点,就是在维护区间的时候,把下标都加一。 * 也就是在存数的时候,num[1] 和 num[n+2] 等于0. * 所有的数都存在 2 ~ n+1 的区间。 * 因为在对区间询问的时候,Q l r * 在调整splay的时候要把 l-1的节点旋转到root,而r+1要转到root下 * 如果是询问整个区间 Q 1 n, 则需要把下标为0的节点旋转至跟。这样就不好维护size域了 * 最后注意输出的时候要long long型的。 */ #include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <string> #include <queue> #include <map> #include <vector> #include <algorithm> #define DEBUG 0 #define INF 0x3fffffff #define OUTSTARS printf("*****************************\n"); #define MAXN 100005 typedef long long LL; using namespace std; struct Splay { LL val, size, add, sum; Splay *son[2], *fa; void init() { size = 1; add = sum = 0; son[0] = son[1] = fa = NULL; } void rot(int c) { Splay *y = fa, *z = fa->fa; y->son[!c] = son[c]; if(son[c]) son[c]->fa = y; fa = z; if(z) { if(z->son[0] == y) z->son[0] = this; else z->son[1] = this; } son[c] = y; y->fa = this; y->update(); } void splay(Splay *pa) { for(push_down(); fa != pa; ) { if(fa->fa == pa) { if(fa->son[0] == this) rot(1); else rot(0); } else { Splay *y = fa, *z = fa->fa; if(z->son[0] == y) { if(y->son[0] == this) { y->rot(1); rot(1); } else { rot(0); rot(1); } } else { if(y->son[1] == this) { y->rot(0); rot(0); } else { rot(1); rot(0); } } } update(); } } void update() { size = 1; sum = val; if(son[0]) { size += son[0]->size; sum += son[0]->sum; } if(son[1]) { size += son[1]->size; sum += son[1]->sum; } } void push_down() { if(!add) return ; if(son[0]) { son[0]->add += add; son[0]->val += add; son[0]->sum += son[0]->size * add; } if(son[1]) { son[1]->add += add; son[1]->val += add; son[1]->sum += son[1]->size * add; } add = 0; } Splay *find(int x) { int L = 0; push_down(); if(son[0]) L += son[0]->size; if(x <= L) return son[0]->find(x); if(x == L + 1) return this; return son[1]->find(x - L - 1); } }tree[MAXN]; int n, m, id; int num[MAXN]; Splay *root; Splay *_alloc() { tree[id].init(); return &tree[id++]; } Splay *build(int l, int r) { if(l > r) return NULL; int mid = (l + r) >> 1; Splay *cur = _alloc(); cur->val = num[mid]; cur->son[0] = build(l, mid - 1); cur->son[1] = build(mid + 1, r); if(cur->son[0]) cur->son[0]->fa = cur; if(cur->son[1]) cur->son[1]->fa = cur; cur->update(); return cur; } void add(int L, int R, int d) { Splay *tmp; tmp = root->find(L - 1); tmp->splay(NULL); root = tmp; tmp = root->find(R + 1); tmp->splay(root); tmp = root->son[1]->son[0]; tmp->push_down(); tmp->add = d; tmp->sum += tmp->size * d; tmp->val += d; } LL query(int L, int R) { Splay *tmp = root->find(L - 1); tmp->splay(NULL); root = tmp; tmp = root->find(R + 1); tmp->splay(root); tmp = root->son[1]->son[0]; return tmp->sum; } int main() { while(~scanf("%d%d", &n, &m)) { id = 0; num[1] = num[n+2] = 0; for(int i = 2; i <= n + 1; i ++) scanf("%d", &num[i]); root = build(1, n + 2); for(int i = 0; i < m; i ++) { getchar(); char cmd = getchar(); if(cmd == 'C') { int l, r, d; scanf("%d%d%d", &l, &r, &d); l ++, r ++; add(l, r, d); } else { int l, r; scanf("%d%d", &l, &r); l ++, r ++; printf("%I64d\n", query(l, r)); } } } return 0; }
POJ A Simple Problem with Integers (Splay 伸展树 入门)
最新推荐文章于 2019-01-04 22:31:07 发布