A Simple Problem with Integers
Time Limit: 5000MS |
| Memory Limit: 131072K |
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
The sums may exceed the range of 32-bit integers.
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 100008
#define lid (id<<1)//左
#define rid (lid|1)//右
typedef long long LL;
struct node
{
int l,r;//左右边界
LL sum;//表示的和
int lazy;//延迟标记
}tr[N*4];
LL a[N];
void push_up(int id)//向上传递
{
tr[id].sum = tr[lid].sum + tr[rid].sum;//一个结点的值等于它左右两边的和
}
void push_down(int id)//向下分解
{
int m=tr[id].r-tr[id].l+1;//类似这个结点的长度
if(tr[id].lazy)//延迟标记不为0
{
tr[lid].lazy+=tr[id].lazy;//延迟标记传给左边
tr[rid].lazy+=tr[id].lazy;//延迟标记传给右边
tr[lid].sum+=(LL)tr[id].lazy*(m-(m>>1));
//左边的值等于它本身加上 添加的值乘长度的一半(也可以理解为它本身的长度)
tr[rid].sum+=(LL)tr[id].lazy*(m>>1);
//右边同理 只不过是剩下的一半
tr[id].lazy=0;//注意 分解之后 延迟标记一定要变回0
}
}
void build(int l,int r,int id)//从上到下建立一棵树
{
tr[id].l = l; tr[id].r = r;//左右边界赋值
tr[id].sum = 0;//和赋值
tr[id].lazy = 0;//延迟标记清零
if( l == r )
{
tr[id].sum=a[l];
return ;//结束条件别忘了
}
int mid=(tr[id].l+tr[id].r)>> 1;//中点
build(l,mid,lid);//左边
build(mid+1,r,rid);//右边
push_up(id);//向上传递
}
void updata(int a,int b,int id,int val)//更新区间内的值
{
if(tr[id].l>=a&&tr[id].r<=b)//恰好是要更新的范围
{
tr[id].lazy+=val;//延迟标记加上更新值
tr[id].sum+=(LL)val*(tr[id].r-tr[id].l+1);//此结点值变为它本身加上它所包含的长度
return ;
}
else
{
push_down(id);//向下分解
int mid=(tr[id].l+tr[id].r)>> 1;//中点
if(a>mid)//区间起点大于中点
{
updata(a,b,rid,val);//全部在右边 更新右
}
else if(b<=mid)//区间终点小于等于终点
{
updata(a,b,lid,val);//全部在左边 更新左
}
else//两边都有
{
updata(a,b,rid,val);
updata(a,b,lid,val);
}//都更新
}
push_up(id);//向上传递
}
LL query(int a,int b,int id,int val)//查询区间值
{
if(tr[id].l>=a&&tr[id].r<=b)//恰好是要查询的区间
return tr[id].sum;//直接返回值
else
{
push_down(id);//查询时也别忘了分解
int mid=(tr[id].l+tr[id].r)>> 1;//中点
if(a>mid)//全在右 查询右
{
return query(a,b,rid,val);
}
else if(b<=mid)//全在左 查询左
{
return query(a,b,lid,val);
}
else//都有 返回两边的和
{
return query(a,b,rid,val)+query(a,b,lid,val);
}
}
}
int main()
{
int n,t;
while(cin>>n>>t)
{
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
build(1,n,1);
while(t--)
{
char op;
cin>>op;
int a,b,val;
if(op=='C')
{
cin>>a>>b>>val;
updata(a,b,1,val);
}
else
{
cin>>a>>b;
printf("%I64d\n",query(a,b,1,val));
}
}
}
return 0;
}
注意:强制类型转换。中间的地方也会超出int范围。