题目大意:给出一个区间,更换某一个子区间中的所有值,所有操作结束后,求区间和
分析:线段树,成段更新。需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or 询问到的时候。
另一篇解题报告讲解较为详细http://blog.csdn.net/hhhhhhj123/article/details/47067873
这里的sum数组和add数组与链接中的讲解有一点不同。sum[i]表示当前结点的区间和,add[i]表示儿子结点的更新值。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 100010; int n, op; int add[4*maxn], sum[4*maxn]; void PushUP(int root) { sum[root] = sum[2*root+1]+sum[2*root+2]; return; } void PushDown(int root, int m) { if(add[root]) { add[2*root+1] = add[2*root+2] = add[root]; sum[2*root+1] = (m-m/2)*add[root]; sum[2*root+2] = m/2*add[root]; add[root] = 0; } } void Build(int root, int l, int r) { add[root] = 0; if(l == r) { sum[root] = 1; } else { Build(2*root+1, l, (l+r)/2); Build(2*root+2, (l+r)/2+1, r); PushUP(root); } return; } void Update(int root, int l, int r, int L, int R, int c) { if(L <= l && r <= R) { add[root] = c; sum[root] = c*(r-l+1); return; } PushDown(root, r-l+1); int m = (l+r)/2; if(L <= m) Update(2*root+1, l, m, L, R, c); if(R > m) Update(2*root+2, m+1, r, L, R, c); PushUP(root); } int main() { int T; scanf("%d", &T); for(int i = 1; i <= T; i++) { scanf("%d%d", &n, &op); Build(0, 1, n); while(op--) { int a, b, c; scanf("%d%d%d", &a, &b, &c); Update(0, 1, n, a, b, c); } printf("Case %d: The total value of the hook is %d.\n", i, sum[0]); } return 0; }