Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 80356 | Accepted: 24812 | |
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
Hint
思路:题目数据量很大,需应用线段树,难点在于对线段树维护过程中的优化。优化通过父亲结点对孩子结点传递数据域的值,同时对父亲结点数据域及时修改。具体方法就是,每次累加一个数字时,没必要把数字一直插入到叶子节点,只要有适合的范围就插入到这个范围中,用一个add记录它,当下一次若有询问时,这个范围若刚好适合询问的范围,就直接把原来这个节点的值加上add乘以范围,再加到result中,就可以了,若这个节点的范围不适合查询的范围的话,就要查询它的子节点了,呢么这时候再把这个add传递给它的子节点,这样在时间上效率就会比较高了。关键是当前结点的sum为当前区间段所有数字的和,add为当前区间中所有数字的待加值,维护的原则是始终保持当前sum和add的正确性。二叉树的整个操作过程均已递归的方式进行,递归过程中只有两种情况,注意思维方式。优化思想与poj2528相似。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100100
using namespace std;
int a[N];
__int64 re;
struct zz
{
int l;
int r;
__int64 m;//m表示区间内的待加值,sum表示当前区间内的和
__int64 sum;
}q[4*N];
void build(int gen,int l,int r)
{
q[gen].l=l;
q[gen].r=r;
q[gen].m=0;
if(l==r)
{
q[gen].sum=a[l];
return ;
}
int mid=(q[gen].l+q[gen].r)/2;
build(gen<<1,l,mid);
build(gen<<1|1,mid+1,r);
q[gen].sum=q[gen<<1].sum+q[gen<<1|1].sum;// 回溯赋值
}
void query(int gen,int l,int r)
{
if(q[gen].l==l&&q[gen].r==r)// 找到整段区间,则累加结果
{
re+=(r-l+1)*q[gen].m+q[gen].sum;
return ;
}
// 待查询区段是当前区间的一部分情况,则修改当前区段和,并将m传入两个孩子结点,后清零当前m,递归继续搜索
q[gen].sum+=(q[gen].r-q[gen].l+1)*q[gen].m;
q[gen<<1].m+=q[gen].m;
q[gen<<1|1].m+=q[gen].m;
q[gen].m=0;
int mid=(q[gen].l+q[gen].r)/2;
if(l<=mid)
query(gen<<1,l,min(r,mid));
if(r>=mid+1)
query(gen<<1|1,max(l,mid+1),r);
}
void update(int gen,int l,int r,__int64 m)
{
if(q[gen].l==l&&q[gen].r==r)// 找到整段区间,则累加m
{
q[gen].m+=m;
return ;
}
//维护思路与查询大致相同,仅增加对m的处理
q[gen].sum+=(q[gen].r-q[gen].l+1)*q[gen].m;// 对当前段的sum累加分两部分
q[gen].sum+=(r-l+1)*m;
q[gen<<1].m+=q[gen].m;
q[gen<<1|1].m+=q[gen].m;
q[gen].m=0;
int mid=(q[gen].l+q[gen].r)/2;
if(l<=mid)
update(gen<<1,l,min(r,mid),m);
if(r>=mid+1)
update(gen<<1|1,max(l,mid+1),r,m);
}
int main()
{
int n,t;
int i;
int x,y;
__int64 z;
char c;
//scanf("%d%d",&n,&t);
while(scanf("%d%d",&n,&t)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
while(t--)
{
getchar();
scanf("%c%d%d",&c,&x,&y);
if(c=='Q')
{
re=0;
query(1,x,y);
printf("%I64d\n",re);
}
else
{
scanf("%I64d",&z);
update(1,x,y,z);
}
}
}
return 0;
}