hdu 1698 Just a Hook[线段树,updata成段更新]

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1698

题目大意:给一个区间1-n,初始化每个值都是1,然后有m个操作,每个操作更新一个区间,输入3个数a, b, c.代表区间a,b的值更新为c。最后求总的值是多少。

思路:线段树成段更新,每一次更新都不需要更新到底部(单点更新),而是更新到tree左端点等于a,右端点等于b即可。

代码:

#include<stdio.h>
#include<string.h>

#define MAXN 100002

int tree[MAXN << 2]; //线段树。
int color[MAXN << 2]; //记录颜色的树,也是一个标记,每次操作都不更新节点,因为直接记录值就能求出最大的。但是本次的结果会影响下一次。这个数组的作用就是对上一次的操作进行更新,但不用更新全部。
int n, m; //n个节点,m次操作。

//向上更新节点。
void PushUp(int rt)
{
	tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}

//向下更新节点。
void PushDown(int rt, int tot)
{
	if( color[rt] ) {
		color[rt << 1] = color[rt];
		color[rt << 1 | 1] = color[rt];
		tree[rt << 1] = (tot - (tot >> 1)) * color[rt];
		tree[rt << 1 | 1] = (tot >> 1) * color[rt];
		color[rt] = 0;
	}
}

void build(int l, int r, int rt)
{
	//在建树的时候,颜色全部为0,因为第一次不用更新,更新操作从第二次开始。
	color[rt] = 0;
	tree[rt] = 1;
	if(l == r) return ;
	int mid = (l + r) >> 1;
	build(l, mid, rt << 1);
	build(mid + 1, r, rt << 1 | 1);
	PushUp( rt );
}

void updata(int L, int R, int value, int l, int r, int rt)
{
	if(L <= l && R >= r) {
		color[rt] = value; //记录当前节点的颜色,但是后面加的是return,并不能执行到PushDown函数。这是因为本次操作不用更行,记录的原因是为了更新下一次。
		tree[rt] = value * (r - l + 1); //本次不用更新的原因就是在这里了,直接赋值就OK了啊。
		return ;
	}
	PushDown(rt, r - l + 1);
	int mid = (l + r) >> 1;
	if(L <= mid) updata(L, R, value, l, mid, rt << 1);
	if(R > mid) updata(L, R, value, mid + 1, r, rt << 1 | 1);
	PushUp( rt );
}

int main()
{
	int T, Case = 0;
	scanf("%d", &T);
	while( T-- ) {
		scanf("%d %d", &n, &m);
		build(1, n, 1);
		for(int i = 0; i < m; i++) {
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			updata(a, b, c, 1, n, 1);
		}
		printf("Case %d: The total value of the hook is %d.\n", ++Case, tree[1]);
	}
	return 0;
}

  

posted @ 2012-11-12 15:38  小猴子、  阅读(345)  评论(0编辑  收藏  举报