| Time Limit: 5000MS | Memory Limit: 131072K | |
| Total Submissions: 66557 | Accepted: 20467 | |
| Case Time Limit: 2000MS | ||
Description
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
Output
You need to answer all Q commands in order. One answer in a line.
Sample Input
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
Sample Output
4 55 9 15
解决方案:此题重点考察的是splay树的区间操作,和线段树有点相似,在节点上加一个add,sum,v标志,当进行旋转,伸展操作时,注意对标志的下移和节点的向上更新。而且建立一个splay树的时候,要直接把区间放在root->ch[1]->ch[0]上,然后通过伸展操作把要查询或更新的区间旋转到root->ch[1]->ch[0]。
code:<pre name="code" class="cpp">#include <iostream> #include<cstdio> #include<algorithm> using namespace std; struct node { node *ch[2]; int s; int v; long long sum; int add; int cmp(int k)const { int d=k-ch[0]->s; if(d==1) return -1; return d<=0?0:1; } void maintain() { s=ch[0]->s+ch[1]->s+1; sum=v+ch[0]->sum+ch[1]->sum; } void updatedown(int c) { v+=c,add+=c,sum+=1LL*s*c; } void pushdown() { if(add) { ch[0]->updatedown(add); ch[1]->updatedown(add); add=0; } } }; node *null=new node(); void rotate(node *&o,int d) { node *k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void splay(node *&o,int k) { o->pushdown(); int d=o->cmp(k); if(d==1) k-=(o->ch[0]->s+1); if(d!=-1) { node *p=o->ch[d]; p->pushdown(); int d2=p->cmp(k); int k2=(d2==0?k:k-p->ch[0]->s-1); if(d2!=-1) { splay(p->ch[d2],k2); if(d==d2) rotate(o,d^1); else rotate(o->ch[d],d); } rotate(o,d^1); } } const int maxn=100000+10; int input[maxn]; struct splaysequence { int n,index; node seq[maxn]; node *root; node *build(int sz) { if(!sz) return null; node *L=build(sz/2); node *o=&seq[++n]; o->v=o->sum=input[index++]; o->ch[0]=L; o->ch[1]=build(sz-sz/2-1); o->s=o->add=0; o->maintain(); return o; } void init(int sz) { index=1; null->add=null->s=null->sum=null->v=0; root=&seq[0]; root->ch[0]=null,root->ch[1]=null; root->add=root->s=root->sum=root->v=0; root->ch[1]=&seq[1]; root->ch[1]->ch[0]=null,root->ch[1]->ch[1]=null; root->ch[1]->add=root->ch[1]->s=root->ch[1]->sum=root->ch[1]->v=0; n=1; root->ch[1]->maintain(); root->maintain(); root->ch[1]->ch[0]=build(sz); } }; void update(node *&root) { int l,r,c; scanf("%d%d%d",&l,&r,&c); splay(root,l); splay(root->ch[1],r-l+2); root->ch[1]->ch[0]->updatedown(c); } void query(node *&root) { int l,r; scanf("%d%d",&l,&r); splay(root,l); splay(root->ch[1],r-l+2); printf("%lld\n",root->ch[1]->ch[0]->sum); } splaysequence ss; int main() { int n,m; while(~scanf("%d%d",&n,&m)) { for(int i=1; i<=n; i++) { scanf("%d",&input[i]); } input[0]=-1; input[n+2]=-1; ss.init(n); for(int i=1; i<=m; i++) { char op[4]; scanf("%s",op); if(op[0]=='Q') { query(ss.root); } else { update(ss.root); } } } return 0; }

本文介绍了一个涉及区间操作的问题,利用Splay树实现高效地对区间内的整数进行加法操作及求和查询。该问题通过Splay树的特性解决了区间更新和查询的难题。
664

被折叠的 条评论
为什么被折叠?



