题目:http://www.gdfzoj.com/oj/contest/285/problems/1
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.求出某区间每一个数的和
简单线段树模板
注意规范(重复向下更新可写个函数(add记得清零)):
void pushdown(int x)
{
if (M[x].add!=0)
{
M[2*x].add+=M[x].add;
M[2*x+1].add+=M[x].add;
M[2*x].sum+=M[x].add*(M[2*x].r-M[2*x].l+1);
M[2*x+1].sum+=M[x].add*(M[2*x+1].r-M[2*x+1].l+1);
M[x].add=0;
}
}
更新add完后记得sum 的pushup!!!
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
long long l,r,add,sum;
};
const int maxS=100000;
int a[maxS+5],n,m;
node M[4*maxS+5];
void pushup(int x)
{
M[x].sum=M[2*x].sum+M[2*x+1].sum;
return ;
}
void pushdown(int x)
{
if (M[x].add!=0)
{
M[2*x].add+=M[x].add;
M[2*x+1].add+=M[x].add;
M[2*x].sum+=M[x].add*(M[2*x].r-M[2*x].l+1);
M[2*x+1].sum+=M[x].add*(M[2*x+1].r-M[2*x+1].l+1);
M[x].add=0;
}
}
void build(int x,int l,int r)
{
int mid=(l+r)/2;
M[x].l=l; M[x].r=r; M[x].add=0;
if (l==r)
{
M[x].sum=a[l];
return ;
}
build(2*x,l,mid);
build(2*x+1,mid+1,r);
pushup(x);
}
void add(int x,int l,int r,int z)
{
int mid=(M[x].l+M[x].r)/2;
if (M[x].l==l && M[x].r==r)
{
M[x].add+=z;
M[x].sum+=(r-l+1)*z;
return ;
}
pushdown(x);
if (r<=mid)
add(2*x,l,r,z);
else if (l>=mid+1)
add(2*x+1,l,r,z);
else
{
add(2*x,l,mid,z);
add(2*x+1,mid+1,r,z);
}
pushup(x);
}
long long query(int x,int l,int r)
{
int mid=(M[x].l+M[x].r)/2;
if (M[x].l==l && r==M[x].r)
return M[x].sum;
pushdown(x);
if (r<=mid)
return query(2*x,l,r);
else if (l>mid)
return query(2*x+1,l,r);
else
return query(2*x,l,mid)+query(2*x+1,mid+1,r);
}
int main()
{
int i,x,y,z,k;
freopen("a.txt","r",stdin);
freopen("b.txt","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
for (i=0;i<m;i++)
{
scanf("%d",&k);
if (k==1)
{
scanf("%d%d%d",&x,&y,&z);
add(1,x,y,z);
}
else
{
scanf("%d%d",&x,&y);
printf("%lld\n",query(1,x,y));
}
}
return 0;
}