题目链接:http://poj.org/problem?id=3468
题目大意:有n个数,标号为1到n;有两种操作 Q i j 代表求i到j的和。
C i j k 代表将i到k中的每个数都加上k。每个Q操作都输出一个结果。
思路:线段树的区间修改和区间求和。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define Max 1e17
#define ll long long
using namespace std;
const int INF=1e6+500;
ll n,q;
struct node{
ll left,right;
ll sum;
ll lazy;
}g[4*INF];
ll a[INF];
char c[5];
void built(ll ans,ll l,ll r)//建树
{
g[ans].left =l;g[ans].right =r;
g[ans].lazy =0;
if(l==r)
{
g[ans].sum =a[l];return;
}
ll mid=(l+r)/2;
built(ans<<1,l,mid);
built(ans<<1|1,mid+1,r);
g[ans].sum =g[ans<<1].sum +g[ans<<1|1].sum ;
}
void pushdown(ll k)//下传标记,更改子区间的值
{
if(g[k].lazy ==0)return ;
ll x=g[k].lazy ;
g[k<<1].sum =g[k<<1].sum+(g[k<<1].right -g[k<<1].left +1)*x ;
g[k<<1|1].sum =g[k<<1|1].sum+(g[k<<1|1].right -g[k<<1|1].left +1)*x ;
g[k<<1].lazy +=g[k].lazy ;
g[k<<1|1].lazy +=g[k].lazy ;
g[k].lazy =0;//清零
}
void update(ll ans,ll l,ll r,ll x)//更新
{
if(g[ans].left >=l&&g[ans].right <=r)//这里不能改为==,原因是下面的子区间判断时,会增加情况(不确定,若改为这样则runtime error)
{
g[ans].sum =g[ans].sum+(g[ans].right -g[ans].left +1)*x ;
g[ans].lazy +=x;//这里时‘+=’的原因是:可能有连续的两个更改区间的操作,
//前一操作时当这个区间满足更新条件更新了,但是其子区间不一定也得到了更新。
return;
}
pushdown(ans);
ll mid=(g[ans].left +g[ans].right )/2;
if(r>mid)update(ans<<1|1,l,r,x);//右儿子是(mid+1,r);
if(l<=mid)update(ans<<1,l,r,x);//左儿子是(l,mid);
g[ans].sum =g[ans<<1].sum +g[ans<<1|1].sum ;
}
ll find(ll ans,ll l,ll r)
{
pushdown(ans);
if(g[ans].left >=l&&g[ans].right <=r)
{
return g[ans].sum ;
}
ll mid=(g[ans].right +g[ans].left )/2;
ll x=0;
if(r>mid)x+=find(ans<<1|1,l,r);
if(l<=mid)x+=find(ans<<1,l,r);
return x;
}
int main()
{
scanf("%lld%lld",&n,&q);
ll i,j,val,k;
ll l;
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
built(1,1,n);
for(i=0;i<q;i++)
{
scanf("%s",c);
if(strcmp(c,"Q")==0)
{
scanf("%lld%lld",&j,&k);
printf("%lld\n",find(1,j,k));
}
else if(strcmp(c,"C")==0)
{
scanf("%lld%lld%lld",&j,&k,&l);
update(1,j,k,l);
}
}
return 0;
}
#include<iostream>//另一种代码 ,两者差不多
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define Max 1e17
#define ll long long
using namespace std;
const int INF=1e6+500;
ll n,q;
struct node{
ll left,right;
ll sum;
ll lazy;
}g[4*INF];
ll a[INF];
char c[5];
void built(ll ans,ll l,ll r)
{
g[ans].left =l;g[ans].right =r;
g[ans].lazy =0;
if(l==r)
{
g[ans].sum =a[l];return;
}
ll mid=(l+r)/2;
built(ans<<1,l,mid);
built(ans<<1|1,mid+1,r);
g[ans].sum =g[ans<<1].sum +g[ans<<1|1].sum ;
}
void pushdown(ll k)
{
if(g[k].lazy ==0)return ;
ll x=g[k].lazy ;
g[k<<1].sum =g[k<<1].sum+(g[k<<1].right -g[k<<1].left +1)*x ;
g[k<<1|1].sum =g[k<<1|1].sum+(g[k<<1|1].right -g[k<<1|1].left +1)*x ;
g[k<<1].lazy +=g[k].lazy ;
g[k<<1|1].lazy +=g[k].lazy ;
g[k].lazy =0;
}
void update(ll ans,ll l,ll r,ll x)
{
if(g[ans].left ==l&&g[ans].right ==r)//这里这样写也可left>=l&&right<=r
{
g[ans].sum =g[ans].sum+(g[ans].right -g[ans].left +1)*x ;
g[ans].lazy +=x;//这里+=的原因是这个区间内的值并没有得到及时的更新,而还会有改变区间数值的操作。
return;
}
pushdown(ans);
ll mid=(g[ans].left +g[ans].right )/2;
if(r<=mid)update(ans<<1,l,r,x);
else if(l>mid)update(ans<<1|1,l,r,x);
else {
update(ans<<1,l,mid,x);
update(ans<<1|1,mid+1,r,x);
}
g[ans].sum =g[ans<<1].sum +g[ans<<1|1].sum ;
}
ll find(ll ans,ll l,ll r)
{
if(g[ans].left ==l&&g[ans].right ==r)//这里这样写也可left>=l&&right<=r
{
return g[ans].sum ;
}
pushdown(ans);
ll mid=(g[ans].right +g[ans].left )/2;
if(r<=mid)return find(ans<<1,l,r);
else if(l>mid)return find(ans<<1|1,l,r);
else return (find(ans<<1,l,mid)+find(ans<<1|1,mid+1,r));
}
int main()
{
scanf("%lld%lld",&n,&q);
ll i,j,val,k;
ll l;
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
built(1,1,n);
for(i=0;i<q;i++)
{
scanf("%s",c);
if(strcmp(c,"Q")==0)
{
scanf("%lld%lld",&j,&k);
printf("%lld\n",find(1,j,k));
}
else if(strcmp(c,"C")==0)
{
scanf("%lld%lld%lld",&j,&k,&l);
update(1,j,k,l);
}
}
return 0;
}