题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31829
思路:线段树。主要是学习一下线段树的区间更新。
描述一下区间更新的方法。查询当前区间是否在要更新的区间内,若在,标记add值为更新值;不在,把要更新区间按照已有线段树的分割方法分割然后向下传递。查询的时候,如果为单点,把单点的值更新为sum+add;add=0;若为区间,返回sum+(R-L+1)*add,不对sum值作处理。
叙述起来是这么的轻松,第一次做却异常艰难。首先是update函数的边界控制,然后是更新区间和更新点值的方法,最后因为query往下传递add时没开成long long又错了一段时间。。。。
源码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
typedef long long ll;
int const MAXN = 100000;
ll sum[MAXN<<2];
ll add[MAXN<<2];
int n,m;
int gmax(int a,int b){return a>b?a:b;}
int gmin(int a,int b){return a<b?a:b;}
void build(int mark,ll now,int L,int R,int st)
{
if(L==R){
sum[st] = now;
return;
}
int mid = (L+R)>>1;
if(mid>=mark) build(mark,now,L,mid,st<<1);
else build(mark,now,mid+1,R,(st<<1)+1);
sum[st] = sum[st<<1] + sum[(st<<1)+1];
}
void maintain(int L, int R,int st)
{
// printf("L = %d, R = %d,st = %d\n",L,R,st);
if(L==R){
sum[st] = sum[st] + add[st];
add[st] = 0;
}
else
sum[st] = sum[st<<1] + sum[(st<<1)+1] + add[st]*(R-L+1);
return;
}
void update(int l,int r,ll now,int L,int R,int st)
{
if(l<=L && r>=R){
// printf("L = %d,R = %d,st = %d,sum = %d\n",L,R,st,sum[st]);
add[st] += now;
maintain(L,R,st);
return;
}
int mid = (L+R)>>1;
if(mid<l) update(l,r,now,mid+1,R,(st<<1)+1);
else if(mid>=r) update(l,r,now,L,mid,(st<<1));
else{
if(mid>=l) update(l,r,now,L,mid,st<<1); /// else maintain(l,mid,st<<1);
if(mid<R) update(l,r,now,mid+1,R,(st<<1)+1);/// else maintain(mid+1,R,(st<<1)+1);
}
maintain(L,R,st);
}
ll query(int l,int r,int L,int R,int st,ll aa)
{
// printf("L = %d,R = %d,st = %d\n",L,R,st);
if(l<=L && r>=R){
// printf("sum = %d,st = %d\n",sum[st],st);
return sum[st]+aa*(R-L+1);
}
int mid = (L+R)>>1;
ll ans = 0;
if(mid>=l) ans += query(l,r,L,mid,st<<1,aa+add[st]);
if(mid<r) ans += query(l,r,mid+1,R,(st<<1)+1,aa+add[st]);
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
int a,b;
ll t,c;
memset(sum,0,sizeof(sum));
memset(add,0,sizeof(add));
for(int i=1; i<=n; i++){
scanf("%I64d",&t);
build(i,t,1,n,1);
}
// for(int i=1; i<(n<<2); i++)
// printf("%02d ",i);
// printf("\n");
// for(int i=1; i<=(n<<2); i++)
// printf("%02I64d ",sum[i]);
// printf("\n");
char temp[5];
for(int i=0; i<m; i++){
scanf("%s%d%d",temp,&a,&b);
if(temp[0]=='Q') printf("%I64d\n",query(a,b,1,n,1,add[1]));
if(temp[0]=='C'){
scanf("%I64d",&c);
update(a,b,c,1,n,1);
// for(int i=1; i<=(n<<2); i++)
// printf("%02I64d ",sum[i]);
// printf("\n");
// for(int i=1; i<=(n<<2); i++)
// printf("%02d ",add[i]);
// printf("\n");
// for(int i=1; i<=(n<<2); i++)
// printf("%02I64d ",sum[i]);
// printf("\n");
}
}
return 0;
}/*
10 6
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
C 3 6 3
C 3 6 -3
C 4 6 -3
Q 2 4
*/