http://poj.org/problem?id=3468
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 4Sample Output
4 55 9 15Hint
The sums may exceed the range of 32-bit integers.
题意:
给定Q (1 ≤ Q ≤ 100,000)个数A1,A2 … AQ,,
以及可能多次进行的两个操作:
1) 对某个区间Ai … Aj的每个数都加n(n可变)
2) 求某个区间Ai … Aj的数的和
思路:用线段树,注意返回值用long long,开的数组是所给范围的4倍
Code:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char str[10];
long long int lazy[400040],sum[400040];///4倍的空间
void build(int l,int r,int o)///建树 l,r 此节点区间长度 o下标
{
if(l==r)///叶节点
{
scanf("%lld",&sum[o]);///直接赋值
return;
}
int mid=(l+r)>>1;
build(l,mid,o<<1);///左
build(mid+1,r,o<<1|1);///右
sum[o]=sum[o<<1]+sum[o<<1|1];///更新此节点的和
}
void pushdown(int o,int l)///o下标 l此节点的区间长度
{
if(lazy[o])///如果此时需要更新操作
{
lazy[o<<1]+=lazy[o];///左
lazy[o<<1|1]+=lazy[o];///右
sum[o<<1]+=lazy[o]*(l-(l>>1));///更新此时 左 的和
sum[o<<1|1]+=lazy[o]*(l>>1);///更新此时 右 的和
lazy[o]=0;///此点位置懒惰标记取消 传到下面两个节点
}
}
void update(int x,int y,int l,int r,int o,int c)///update(l,r,1,n,1,c);
{///x,y操作区间 l,r树的范围 o下标 c具体操作(+c)
if(x<=l&&y>=r)///操作区间全在树的范围内
{
sum[o]+=(r-l+1)*c;///对此时sum[o]进行更新操作
lazy[o]+=c;///并懒惰标记
return ;
}
pushdown(o,r-l+1);///不符合 就push懒惰标记
int mid=(l+r)>>1;
if(x<=mid)update(x,y,l,mid,o<<1,c);///更新左
if(y>mid)update(x,y,mid+1,r,o<<1|1,c);///更新右
sum[o]=sum[o<<1]+sum[o<<1|1];///更新此节点的和
}
long long int query(int x,int y,int l,int r,int o)
{///x,y操作区间 l,r树的范围 o下标
if(x<=l&&y>=r)///全包含 就输出此时区间的和
return sum[o];
pushdown(o,r-l+1);///懒惰标记函数
int mid=(r+l)>>1;
long long sum=0;///long long型
if(x<=mid)sum+=query(x,y,l,mid,o<<1);///说明 树的左边与操作区间有交集
if(y>mid)sum+=query(x,y,mid+1,r,o<<1|1);///o<<1|1 位运算比+-快
return sum;
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
memset(lazy,0,sizeof(lazy));
memset(sum,0,sizeof(sum));
build(1,n,1);///建树
while(m--)
{
int l,r,c;
scanf("%s",&str);///字符串避免回车符
if(str[0]=='Q')
{
scanf("%d %d",&l,&r);
printf("%lld\n",query(l,r,1,n,1));///查询函数
}
else
{
scanf("%d %d %d",&l,&r,&c);
update(l,r,1,n,1,c);///操作更新函数
}
}
}
return 0;
}
附图:
↖(^ω^)↗
加油!~
压力就是比你优秀一百倍的人比你还在努力!~