poj 3468 A Simple Problem with Integers

// 题意: 序列A[1-N], (1) C a b c 表示区间[a,b]里的数都加上c, (2) Q a b 查询区间[a,b]各个数的和

#include <iostream> // 线段树, 修改和查询区间
using namespace std;

struct segment
{
int l,r;
__int64 sum,off; // sum记录该区间的和, 当覆盖范围为整个区间时,off记录所有的偏移量c, off初始化默认为0
}tree[400000];

int arr[100005],c;
void built_tree(int n, int s,int t)
{
tree[n].l=s;
tree[n].r=t;
if(s==t)
tree[n].sum=arr[s];
else
{
int mid=(s+t)>>1;
built_tree(2*n,s,mid);
built_tree(2*n+1,mid+1,t);
tree[n].sum=tree[2*n].sum+tree[2*n+1].sum;
}
}
void modify(int n, int s,int t)
{
tree[n].sum+=(t-s+1)*c;
if(s==tree[n].l&&t==tree[n].r) //当覆盖整个区间时,off 记录偏移量,而且不必再继续往下修改了。如果一直修改到叶子节点,会TLE
tree[n].off+=c;

else
{
int mid=(tree[n].l+tree[n].r)>>1;
if(s<=mid)
modify(2*n,s,min(mid,t));
if(t>mid)
modify(2*n+1,max(mid+1,s),t);
}
}
__int64 query(int n, int s,int t)
{
if(s==tree[n].l&&t==tree[n].r) //当询问的范围为整个区间时,直接返回该区间的总和
return tree[n].sum;

else
{
int mid=(tree[n].l+tree[n].r)>>1;
__int64 a=0,b=0;
if(s<=mid)
a=query(2*n,s,min(mid,t));
if(t>mid)
b=query(2*n+1,max(mid+1,s),t);
return a+b+(t-s+1)*tree[n].off;

//要加上(t-s+1)*tree[n].off 的偏移量,因为如果之前修改了tree[n]整个区间,
//那么在tree[2*n].sum 或 tree[2*n+1].sum中是无法反映出来的
}

}
int main()
{
int n,q,s,t;
scanf("%d%d",&n,&q);
char ch[2];
for(int i=1;i<=n;++i)
scanf("%d",arr+i);
built_tree(1,1,n);
while (q--)
{
scanf("%s",ch);
if(ch[0]=='Q')
{
scanf("%d%d",&s,&t);
printf("%I64d\n",query(1,s,t));
}
else
{
scanf("%d%d%d",&s,&t,&c);
modify(1,s,t);
}
}
return 0;
}

posted on 2011-07-18 00:10  sysu_mjc  阅读(147)  评论(0编辑  收藏  举报

导航