这是我的第一道线段树懒操作,2次TLE,6次WA之后,终于AC了。
其实题目本身没有那么难,不过因为是第一次写,所以很多细节都没注意到。
我在写另一道hdu上的题目的时候,我没有查资料,一直自己yy懒操作该是怎么样。当时我想的是应该是在结点里放一个flag,用来存储对这个结点的子树的更新信息。在更新的时候这个信息并不往下传递,仅仅只是存下来,在需要查询的时候再传递。实际上我想的基本没错,但是当时一个问题卡住我了,那就是,如果我需要查询左子树的值,这时候flag的值需要往左子树更新,那么树根上的flag的值就需要清0。但是右子树怎么办?
这个问题我一直没想到怎么解决,知道我看了别人的思路。。。。。原来只要将这个父节点的flag的值同时传递到它的左右子树就行了。亏我想了那么久,脑子抽筋了。
其他的操作就是线段树的常规操作做了一些小修改,没有什么特别值得一说的地方了。
#include<stdio.h>
#include<string.h>
#define N 100005
struct node
{
int x,y;
__int64 sum;
__int64 flag;
}a[N*3];
int b[N];
void Bulid_Tree(int t,int x,int y)
{
a[t].x=x;
a[t].y=y;
a[t].flag=0;
if(x==y)
{
a[t].sum=b[x];
return ;
}
int temp=t*2;
int mid=(x+y)/2;
Bulid_Tree(temp,x,mid);
Bulid_Tree(temp+1,mid+1,y);
a[t].sum=a[temp].sum+a[temp+1].sum;
return ;
}
void Update_Tree(int t,int x,int y,__int64 flag)
{
if(a[t].x==x&&a[t].y==y)
{
a[t].flag+=flag;
return ;
}
a[t].sum=a[t].sum+(y-x+1)*flag;
int temp=t*2;
int mid=(a[t].x+a[t].y)/2;
if(y<=mid)
Update_Tree(temp,x,y,flag);
else if(x>mid)
Update_Tree(temp+1,x,y,flag);
else
{
Update_Tree(temp,x,mid,flag);
Update_Tree(temp+1,mid+1,y,flag);
}
return ;
}
__int64 Find_Tree(int t,int x,int y)
{
__int64 sum=0;
if(a[t].x==x&&a[t].y==y)
return a[t].sum+(a[t].y-a[t].x+1)*a[t].flag;
int temp=t*2;
int mid=(a[t].x+a[t].y)/2;
a[temp].flag+=a[t].flag;
a[temp+1].flag+=a[t].flag;
a[t].sum=a[t].sum+(a[t].y-a[t].x+1)*a[t].flag;
a[t].flag=0;
if(y<=mid)
sum+=Find_Tree(temp,x,y);
else if(x>mid)
sum+=Find_Tree(temp+1,x,y);
else
{
sum+=Find_Tree(temp,x,mid);
sum+=Find_Tree(temp+1,mid+1,y);
}
return sum;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
int i;
for(i=1;i<=n;i++)
scanf("%d",&b[i]);
Bulid_Tree(1,1,n);
getchar();
while(m--)
{
char c;
scanf("%c",&c);
if(c=='Q')
{
int x,y;
scanf("%d%d",&x,&y);
getchar();
printf("%I64d\n",Find_Tree(1,x,y));
}
else
{
int x,y;
__int64 z;
scanf("%d%d%I64d",&x,&y,&z);
getchar();
Update_Tree(1,x,y,z);
}
}
}
return 0;
}