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; }