该题是线段树区间修改和区间查询的模板题,需要仔细理解模板中的setv数组和sumv数组,sumv数组定义为:如果只执行结点o及其子孙结点中的setv操作,结点o对应区间中所有数只和。 setv数组就是所谓的懒惰标记,我们不是每次修改值都遍历所有涉及到的区间,而是在查询时用到了哪个setv值之时临时更新。
还有一些细节没有搞懂,明白之后再回来补充。
细节参见代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int maxn = 100000 + 5;
int T,n,q,y11,y22,v,kase=0,_sum,sumv[3*maxn],setv[maxn*3];
void pushdown(int o) {
int lc = o*2, rc = o*2+1;
if(setv[o] >= 0) {
setv[lc] = setv[rc] = setv[o];
setv[o] = -1;
}
}
void maintain(int o, int L, int R) {
int lc = o*2, rc = o*2+1;
sumv[o] = 0;
if(R > L) {
sumv[o] = sumv[lc] + sumv[rc];
}
if(setv[o]>=0) sumv[o] = setv[o]*(R-L+1);
}
void update(int o, int L, int R) {
int lc = o*2, rc = o*2+1;
if(y11 <= L && y22 >= R) {
setv[o] = v;
} else {
pushdown(o);
int M = L + (R-L)/2;
if(y11 <= M) update(lc, L, M); else maintain(lc, L, M);
if(y22 > M) update(rc, M+1, R); else maintain(rc, M+1, R);
}
maintain(o, L, R);
}
void query(int o, int L, int R) {
if(setv[o] >= 0) {
_sum += setv[o] * (min(R,y22)-max(L,y11)+1);
} else if(y11 <= L && y22 >= R) {
_sum += sumv[o];
} else {
int M = L + (R-L)/2;
if(y11 <= M) query(o*2, L, M);
if(y22 > M) query(o*2+1, M+1, R);
}
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&q);
v = 1; y11 = 1; y22 = n;
update(1,1,n);
while(q--) {
scanf("%d%d%d",&y11,&y22,&v);
update(1,1,n);
} _sum = 0;
y11 = 1; y22 = n;
query(1,1,n);
printf("Case %d: The total value of the hook is %d.\n",++kase,_sum);
}
return 0;
}