题目大意:给出一个区间,更换某一个子区间中的所有值,所有操作结束后,求区间和
分析:线段树,成段更新。需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新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;
}