pku3468: http://poj.org/problem?id=3468
题意:给定一段区间,其初始数值给定,Q [a,b]表示求区间[a,b]的和,C [a,b]c表示将区间[a,b]的所有数值加上c
解法:线段树lazy思想:由于整段要更新,所以每次只需更新父节点,并用lazy标记,当遇到lazy!=0时,更新下一代,同时标记,这样一直往下更新。
code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
struct abc
{
__int64 num,lazy;
int l,r;
}v[300009];
int w[100009];
void build(int s,int t,int n) //建树并放入给定数值
{
v[n].l=s;
v[n].r=t;
v[n].lazy=0;
int mid=(s+t)/2;
if(s==t)
{
v[n].num=w[s];
return;
}
build(s,mid,n*2);
build(mid+1,t,n*2+1);
v[n].num=v[n*2].num+v[n*2+1].num; //从下往上更新
}
void insert(int s,int t,int a,int n) //插入:lazy
{
if(v[n].l>=s&&v[n].r<=t) //若给定范围包含n的范围,用lazy标记该点已更新
{
v[n].lazy+=a;
v[n].num+=(v[n].r-v[n].l+1)*a;
return;
}
if(v[n].lazy) //若父节点有更新,子节点也跟着更新,n的lazy=0
{
v[n*2].lazy+=v[n].lazy;
v[n*2].num+=(v[n*2].r-v[n*2].l+1)*v[n].lazy;
v[n*2+1].lazy+=v[n].lazy;
v[n*2+1].num+=(v[n*2+1].r-v[n*2+1].l+1)*v[n].lazy;
v[n].lazy=0;
}
int mid=(v[n].l+v[n].r)/2;
if(t<=mid)
insert(s,t,a,2*n);
else if(s>=mid+1)
insert(s,t,a,2*n+1);
else
{
insert(s,mid,a,2*n);
insert(mid+1,t,a,2*n+1);
}
v[n].num=v[n*2].num+v[n*2+1].num; //从下往上更新父节点
}
__int64 sum(int s,int t,int n) //求和
{
if(v[n].l==s&&v[n].r==t)
return v[n].num;
if(v[n].lazy) //若还有未更新下代的节点,往下更新
{
v[n*2].lazy+=v[n].lazy;
v[n*2].num+=(v[n*2].r-v[n*2].l+1)*v[n].lazy;
v[n*2+1].lazy+=v[n].lazy;
v[n*2+1].num+=(v[n*2+1].r-v[n*2+1].l+1)*v[n].lazy;
v[n].lazy=0;
}
int mid=(v[n].l+v[n].r)/2;
if(t<=mid)
return sum(s,t,2*n);
else if(s>mid)
return sum(s,t,2*n+1);
else
return sum(s,mid,2*n)+sum(mid+1,t,2*n+1);
}
int main()
{
int q,a,b,c,n;
char ch;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
build(1,n,1);
getchar();
for(int i=0;i<q;i++)
{
scanf("%c",&ch);
if(ch=='Q')
{
scanf("%d%d",&a,&b);
printf("%I64d\n",sum(a,b,1));
}
else
{
scanf("%d%d%d",&a,&b,&c);
insert(a,b,c,1);
}
getchar();
}
}
/*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
output:
4
55
9
15*/