poj3468

回家2天多,都在搞线段树了,第一是回家效率也不是很高,第二是线段树也不是很容易搞,前面说了poj2777的一道线段树,那题需要lazy,现在觉得,要是不用lazy的线段树好像不是很正规似的。这里突然想到一点,其实有些做法是无法用lazy实现的,像前面那题着色,单单只是覆盖,比如说你在一个区间多次覆盖了不同的颜色,但是你需要查询该区间的左右儿子时,你传递过去的只是最新的那个颜色,这样是比较容易实现的,再说说poj3468这题,试着考虑刚才类似的问题,假如我多次向某个区间做了add操作,那么那个区间节点该保存什么呢,当然是所有加的数的和,所以这里add是需要累加的,其实对它的儿子节点来说,就是加a,加b,等价于一次性把a+b都加上了。但是我想肯定有些操作是无法lazy的,但是我好像没想出来。

poj3468代码如下

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
	int l,r;
	long long add,sum;
}tr[500001];
int a[100001];
void cre(int l,int r,int node)
{
	tr[node].l=l;
	tr[node].r=r;
	tr[node].add=0;
	tr[node].sum=0;
	if(l==r)
		return ;
	int mid=(l+r)/2;
	cre(l,mid,node*2);
	cre(mid+1,r,node*2+1);
	return ;
}
long long getsum(int l,int r,int node)
{
	if(l==tr[node].l&&tr[node].r==r)
		return tr[node].sum;
	if(tr[node].add!=0)
	{
		tr[2*node].add+=tr[node].add;
		tr[2*node+1].add+=tr[node].add;
		tr[2*node].sum+=tr[node].add*(tr[2*node].r-tr[2*node].l+1);
		tr[2*node+1].sum+=tr[node].add*(tr[2*node+1].r-tr[2*node+1].l+1);
		tr[node].add=0;
	}
	int mid=(tr[node].l+tr[node].r)/2;
	long long c,c1,c2;
	if(l>mid)
		c=getsum(l,r,2*node+1);
	else if(r<=mid)
		c=getsum(l,r,2*node);
	else 
	{
		c1=getsum(l,mid,2*node);
		c2=getsum(mid+1,r,2*node+1);
		c=c1+c2;
	}
	return c;
}
long long upd(int l,int r,int ad,int node)
{
	if(l==tr[node].l&&tr[node].r==r)
	{
		tr[node].add+=ad;
		tr[node].sum+=ad*(r-l+1);
		return tr[node].sum;
	}
	if(tr[node].add!=0)
	{
		tr[2*node].add+=tr[node].add;
		tr[2*node+1].add+=tr[node].add;
		tr[2*node].sum+=tr[node].add*(tr[2*node].r-tr[2*node].l+1);
		tr[2*node+1].sum+=tr[node].add*(tr[2*node+1].r-tr[2*node+1].l+1);
		tr[node].add=0;
	}
	int mid=(tr[node].l+tr[node].r)/2;
	long long c1,c2;
	if(mid>=r)
	{
		c1=upd(l,r,ad,2*node);
		c2=getsum(mid+1,tr[node].r,2*node+1);
	}
	else if(mid<l)
	{
		c1=getsum(tr[node].l,mid,2*node);
		c2=upd(l,r,ad,2*node+1);
	}
	else
	{
		c1=upd(l,mid,ad,2*node);
		c2=upd(mid+1,r,ad,2*node+1);
	}
	tr[node].sum=c1+c2;
	return tr[node].sum;	
}	

int n,o;
int main()
{
	while(~scanf("%d%d",&n,&o))
	{
		int i;
		cre(1,n,1);
		for(i=1;i<=n;i++)
		{
			scanf("%d",a+i);
			upd(i,i,a[i],1);
		}
		while(o--)
		{
			int a,b,c;
			char op[2];
			scanf("%s",op);
			if(op[0]=='C')
			{
				scanf("%d%d%d",&a,&b,&c);
				upd(a,b,c,1);
			}
			else if(op[0]=='Q')
			{
				scanf("%d%d",&a,&b);
				printf("%lld\n",getsum(a,b,1));
			}
		}
	}
	return 0;
}


你可能感兴趣的:(线段树)