题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698
题目大意:一题关于Dota的题,寂寞的男人玩Dota,空虚的男人做Dota题。言归正传,本题给定一个长度为n的序列,每个位置初始化都为1,现在有q个操作,可以将某段区间的数全部赋为1或2或3,问最后的序列总和是多少。
解题思路:很早之前用暴力的方法才能背后往前面操作过了这题,这种解法利用了某段区间如果在后面被操作过,那么前面的操作就无效,这样枚举每个i位置,看最后一次操作是变成1还是2还是3,如果没操作那就是默认1,用了203ms。
前几天在金华邀请赛中碰到一题用线段树解的题目,是成段更新的,不会做。比赛完看了些文章,果断开始做这题成段更新入门题。第一次写成段更新的解题报告,写的详细些,后面有新的领悟,也都在这篇文章修改。单点更新是更新叶子节点,然后再从叶子一层一层往回更新到根,但是成段更新也这样的话复杂度太高,一些更新根本没必要,比如说很多情况下不必更新到叶子节点。这里引入lazy数组,表示这个节点是否可以延迟操作。如果可以延迟操作,那么本次更新就到此为止,不必更新子节点。如果下次要更新或者查询它的子节点再修改lazy值,然后更新子节点。傻仔(大二大三进总决赛,大四无奈退役的男人)概括了下:简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候。具体得实现是:在更新节点时,判断我们查询到的节点是否在题目要求的更新范围内,如果在则标记(改变lazy值),如果不在则判断这个节点在之前的操作中是否被标记,如果之前被标记,去除标记,将标记移到子节点中,因为子节点也是要被更新的,只是之前父节点被标记(用它丰厚的羽翼保护了子节点)。
下面的这段代码是我在杭州用记事本敲得,没有编译器,只能通过hdu来判断写的是否正确,8A。后面在看别人解题报告时发现一个输入优化,因为每个输入的数都是整数,可以用getchar不用scanf,速度快了一半,具体见代码。
测试数据:
3
10
2
1 5 2
5 9 3
10
3
1 5 3
1 5 2
1 5 1
10
5
1 4 2
2 4 3
1 2 3
5 6 1
5 9 3
代码:
#include <stdio.h> #include <string.h> #define MAX 110000 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int n,sum[MAX*3]; int q,lazy[MAX*3]; void PushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void build(int l,int r,int rt) { lazy[rt] = 0; if (l == r) { sum[rt] = 1; return; } int m = (l + r) >> 1; build(lson); build(rson); PushUp(rt); } void PushDown(int rt,int tot) { if (lazy[rt] != 0) { lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt]; sum[rt<<1] = lazy[rt] * (tot - (tot >> 1)); sum[rt<<1|1] = lazy[rt] * (tot >> 1); lazy[rt] = 0; } } void update(int L,int R,int add,int l,int r,int rt) { if (l >= L && r <= R) { lazy[rt] = add; sum[rt] = add * (r - l + 1); return; } int m = (l + r) >> 1; PushDown(rt,r-l+1); if (m >= L) update(L,R,add,lson); if (m < R) update(L,R,add,rson); PushUp(rt); } int getval(){ char c; int ret=0; while((c=getchar())!=' '&&c!='\n') ret=ret*10+(c-'0'); return ret; } int main() { int i,j,k,t,cas = 0; t = getval(); while (t--) { n = getval(); build(1,n,1); q = getval(); for (i = 1; i <= q; ++i) { int a,b,c; a = getval(); b = getval(); c = getval(); update(a,b,c,1,n,1); } printf("Case %d: The total value of the hook is %d.\n",++cas,sum[1]); } }
本文ZeroClock原创,但可以转载,因为我们是兄弟。