伸展数最基本操作的模板,区间求和,区间更新。为了方便理解,特定附上一自己搞的搓图
这是样例中的数据输入后建成的树,其中的1,2是加入的边界顶点,数字代表节点编号,我们如果要对一段区间[l, r]进行操作,只需要把第l-1位的数旋转到0节点下面,把r+1位的数旋转到当前的root下面,就如上图所示,那么椭圆里表示的就是区间[l, r]。
附上注释代码。指针版本的比静态数组的快1s多。。
/* ********************************************** Author : JayYe Created Time: 2013-8-16 11:14:36 File Name : zzz.cpp *********************************************** */ #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define LL __int64 #define keytree (ch[ ch[root][1] ][0]) #define lson ch[x][0] #define rson ch[x][1] const int maxn = 111111; struct Splaytree { int pre[maxn], ch[maxn][2], sz[maxn]; int root, top; // 旋转操作, c = 0代表左旋, c = 1代表右旋 void Rotate(int x, int c) { int y = pre[x]; push_down(y), push_down(x); ch[y][!c] = ch[x][c]; pre[ch[x][c]] = y; if(pre[y]) ch[pre[y]][ ch[pre[y]][1] == y ] = x; pre[x] = pre[y]; ch[x][c] = y; pre[y] = x; push_up(y); } // Splay 操作, 把 x 节点转到go的下面 void Splay(int x, int go) { while(pre[x] != go) { if(pre[pre[x]] == go) { Rotate(x, ch[pre[x]][0] == x); } else { int y = pre[x] , z = pre[y]; int f = (ch[z][1] == y); if(ch[y][f] == x) Rotate(y, !f), Rotate(x, !f); // 一字型旋转 else Rotate(x, f), Rotate(x, !f); // 之字型旋转 } } push_up(x); if(go == 0) root = x; } // 将第k位的数旋转到go的下面 void RotateTo(int k, int go) { int x = root; push_down(root); while(sz[lson] != k) { if(k < sz[lson]) { x = lson; } else { k -= sz[lson] + 1; x = rson; } push_down(x); } Splay(x, go); } void debug() {printf("%d\n",root);Treaval(root);} void Treaval(int x) { if(x) { Treaval(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d\n",x,ch[x][0],ch[x][1],pre[x],sz[x],val[x]); Treaval(ch[x][1]); } } int val[maxn], add[maxn], a[maxn]; LL sum[maxn]; // 把儿子节点的信息更新上来 void push_up(int x) { sz[x] = sz[lson] + sz[rson] + 1; sum[x] = val[x] + add[x] + sum[lson] + sum[rson]; } // 标记下传 void push_down(int x) { if(add[x]) { val[x] += add[x]; add[lson] += add[x]; add[rson] += add[x]; sum[lson] += (LL)add[x]*sz[lson]; sum[rson] += (LL)add[x]*sz[rson]; add[x] = 0; } } void newnode(int &x, int c) { x = ++top; lson = rson = 0; sz[x] = 1; val[x] = sum[x] = c; add[x] = 0; } void build(int &x, int l, int r, int f) { if(l > r) return ; int mid = (l+r)/2; newnode(x, a[mid]); build(lson, l, mid-1, x); build(rson, mid+1, r, x); pre[x] = f; push_up(x); } void init(int n) { ch[0][0] = ch[0][1] = pre[0] = 0; top = root = 0; newnode(root, -1); newnode(ch[root][1], -1); // 为了方便处理边界,加两个边界顶点 pre[top] = root; sz[root] = 2; for(int i = 0;i < n; i++) scanf("%d", &a[i]); build(keytree, 0, n-1, ch[root][1]); push_up(ch[root][1]); push_up(root); } void update(int l ,int r, int c) { RotateTo(l-1, 0); RotateTo(r+1, root); add[keytree] += c; sum[keytree] += (LL)c*sz[keytree]; } LL query(int l, int r) { RotateTo(l-1, 0); RotateTo(r+1, root); return sum[keytree]; } }spt; int main() { int n, m, l, r, c; char s[2]; scanf("%d%d", &n, &m); spt.init(n); while(m--) { scanf("%s%d%d", s, &l, &r); if(s[0] == 'Q') printf("%I64d\n", spt.query(l, r)); else { scanf("%d", &c); spt.update(l, r, c); } } return 0; }
/* ********************************************** Author : JayYe Created Time: 2013-8-16 15:19:38 File Name : zzz.cpp *********************************************** */ #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define LL __int64 #define keytree (root->ch[1]->ch[0]) #define lson x->ch[0] #define rson x->ch[1] const int maxn = 111111; struct NODE { struct NODE *ch[2], *pre; int add, val, sz, id; LL sum; void push_down() { if(add) { val += add; if(ch[0]) { ch[0]->add += add; ch[0]->sum += (LL)add*ch[0]->sz; } if(ch[1]) { ch[1]->add += add; ch[1]->sum += (LL)add*ch[1]->sz; } add = 0; } } void push_up() { sz = ch[0]->sz + ch[1]->sz + 1; sum = val + add + ch[0]->sum + ch[1]->sum; } }node[maxn], *null = &node[0], *root; struct Splaytree { int top; // 旋转操作, c = 0代表左旋, c = 1代表右旋 void Rotate(NODE *x, int c) { NODE *y = x->pre; y->push_down(), x->push_down(); y->ch[!c] = x->ch[c]; x->ch[c]->pre = y; x->pre = y->pre; if(y->pre != NULL) y->pre->ch[ y->pre->ch[1] == y] = x; x->ch[c] = y; y->pre = x; y->push_up(); } // Splay 操作, 把 x 节点转到go的下面 void Splay(NODE *x, NODE *go) { while(x->pre != go) { if(x->pre->pre == go) { Rotate(x, x->pre->ch[0] == x); } else { NODE *y = x->pre, *z = y->pre; int f = (z->ch[1] == y); if(y->ch[f] == x) Rotate(y, !f) , Rotate(x, !f); // 一字型旋转 else Rotate(x, f) , Rotate(x, !f); // 之字型旋转 } } x->push_up(); if(go == null) root = x; } // 将第k位的数旋转到go的下面 void RotateTo(int k, NODE *go) { NODE *x = root; x->push_down(); while(lson->sz != k) { if(lson->sz > k) { x = lson; } else { k -= lson->sz + 1; x = rson; } x->push_down(); } Splay(x, go); } void debug(NODE *x) { if(x != null) { printf("节点: %2d 左儿子: %2d 右儿子: %2d size = %2d val = %2d\n", x->id, x->ch[0]->id, x->ch[1]->id, x->sz, x->val); debug(x->ch[0]); debug(x->ch[1]); } } int a[maxn]; NODE *newnode(NODE* f, int c) { NODE *x = &node[++top]; x->id = top; x->val = x->sum = c; x->ch[0] = x->ch[1] = null; x->sz = 1; x->add = 0; x->pre = f; return x; } void build(NODE* &x, int l, int r, NODE *f) { if(l > r) return ; int mid = (l+r)/2; x = newnode(f, a[mid]); build(lson, l, mid-1, x); build(rson, mid+1, r, x); x->push_up(); } void init(int n) { null->id = 0; null->ch[0] = null->ch[1] = NULL; null->sz = null->add = null->sum = null->val = 0; // null->pre = NULL; top = 0; root = newnode(null, -1); root->ch[1] = newnode(root, -1); for(int i = 0;i < n; i++) scanf("%d", &a[i]); build(keytree, 0, n-1, root->ch[1]); root->ch[1]->push_up(); root->push_up(); } void update() { int l, r, c; scanf("%d%d%d", &l, &r, &c); RotateTo(l-1, null); RotateTo(r+1, root); keytree->add += c; keytree->sum += (LL)c*keytree->sz; } void query() { int l, r; scanf("%d%d", &l, &r); RotateTo(l-1, null); RotateTo(r+1, root); printf("%I64d\n", keytree->sum); } }spt; int main() { int n, m; char s[2]; scanf("%d%d", &n, &m); spt.init(n); while(m--) { scanf("%s", s); if(s[0] == 'Q') spt.query(); else spt.update(); } return 0; }