hdu1698(线段树懒惰法)

http://acm.hdu.edu.cn/showproblem.php?pid=1698

大意:给一组棍子染色,不同的颜色有不同的值,执行一系列的区间染色后,问这组棍子的总值是多少。

题目分析:建树:节点的域有左右节点和颜色,l,r,num;num=0时表示这个区间由多种颜色覆盖。

更新的时候,如果更新区间比当前区间小,并且当前区间的颜色大于0,说明已经被完全染色,就把该区间颜色传递到左右子树上,该区间染色为0,然后根据更新区间的大小,在左右子树上去搜索。

求和的时候遇到区间的num>0的时候说明完全被染色过了,就把区间的长度乘以颜色的值加到总和里面去,然后结束这个方向的递归查询,

代码:

#include<iostream>
using namespace std;
struct node
{
	int l,r,num;
}tree[400000];
int ans;
void build(int i,int l,int r)
{
	tree[i].l=l;
	tree[i].r=r;
	tree[i].num=1;
	if(l==r)
		return;
	else
	{
		int mid=(l+r)/2;
		build(i*2,l,mid);
		build(i*2+1,mid+1,r);
	}
}
void updata(int i,int l,int r,int v)
{
	if(l==tree[i].l&&r==tree[i].r)
	{
		tree[i].num=v;
		return;
	}
	if(tree[i].num==v)
		return ;
	if(tree[i].num>0)                 
	{
		tree[i*2+1].num=tree[i*2].num=tree[i].num;
		tree[i].num=0;
	}
	int mid=(tree[i].l+tree[i].r)/2;
	if(r<=mid)
	{
		updata(i*2,l,r,v);
	}
	else
		if(l>mid)
			updata(i*2+1,l,r,v);
		else
		{
			updata(i*2,l,mid,v);
			updata(i*2+1,mid+1,r,v);
		}
}
void getsum(int i,int l,int r)
{
	if(tree[i].num>0)
	{
		ans+=(tree[i].r-tree[i].l+1)*tree[i].num;    //注意,要加1
		return ;
	}
	else
	{
		int mid=(tree[i].l+tree[i].r)/2;
		if(r<=mid)
			getsum(i*2,l,r);
		else
			if(l>mid)
				getsum(i*2+1,l,r);
			else
			{
				getsum(i*2,l,mid);
				getsum(i*2+1,mid+1,r);
			}
	}

}
int main()
{
	int t,k=0;;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		int m;
		scanf("%d",&m);
		build(1,1,n);
		while(m--)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			updata(1,x,y,z);
		}
		ans=0;
		getsum(1,1,n);
		printf("Case %d: The total value of the hook is %d.\n",++k,ans); 
	}
	return 0;
}

 

posted @ 2012-11-23 12:21  紫忆  阅读(354)  评论(0编辑  收藏  举报