题意
给你个大区间,区间上初始值皆为1,然后给出一系列修改操作,查询操作。
修改操作可修改区间l~r上的值为k(1,2,3),查询操作问区间 l ~ r上的数值总和为多少。
解释
利用线段树,求和版本,但利用lazy标记,lazy只标记在符合更新的区间内的区间点。然后在query里写在向下更新前,进行pushdown的lazy更新。pushdown中利用lazy得到子节点的lazy值,同时为两个子区间节点的值赋值成(或加上)对应区间应得的值。
在update中对由于当前子区间在范围内,给lazy重新赋值,即使前面该lazy也被赋值过,但结果以后更新为准,这样就减少了更新,达成了lazy的作用。
在查询中,也是需要用到查询的区间,lazy才往下pushdown,尽量减少不必要的操作得到结果。
#include <cstdio>
int num[100001*4];
int lazy[100001*4];
void bulit(int l, int r,int ret){
int m = (l+r)/2;
lazy[ret] = 0;
if(r == l){
num[ret] = 1;
return ;
}
bulit(l, m, ret*2);
bulit(m+1, r, ret*2+1);
num[ret] = num[ret*2] + num[ret*2+1];
}
void pushdown(int l, int r, int ret){
if(lazy[ret]){
lazy[ret*2] = lazy[ret*2+1] = lazy[ret];
int m = (l+r)/2;
num[ret*2] = (m-l+1)*lazy[ret];
num[ret*2+1] = (r-(m+1)+1)*lazy[ret];
lazy[ret] = 0;
}
}
void change(int L, int R, int l, int r, int key, int ret){
int m = (l+r)/2;
if(L<= l&& r<= R){
lazy[ret] = key;
num[ret] = (r-l+1)*key;
return ;
}
pushdown(l, r, ret);
if(L<= m) change(L, R, l, m, key, ret*2);
if(R> m) change(L, R, m+1, r, key, ret*2+1);
num[ret] = num[ret*2] + num[ret*2+1];
}
int ans = 0;
int query(int L, int R, int l, int r, int ret){
int ans = 0;
int m = (l+r)/2;
if(L <= l && r <= R){
return num[ret];
}
pushdown(l, r, ret);
ans = 0;
m = (l+r)>>1;
if(L <= m) ans += query(L, R, l, m, ret*2);
if(R >= m+1) ans += query(L, R, m+1, r, ret*2+1);
return ans;
}
int main(){
int t;
int n, m;
int r, l, v;
scanf("%d", &t);
int cont = 1;
while(t--){
scanf("%d %d", &n,&m);
bulit(1, n, 1);
for(int i = 0; i < m; i++)
{
scanf("%d %d %d", &l, &r, &v);
change(l, r, 1, n, v,1);
}
printf("Case %d: The total value of the hook is %d.\n",cont++, query(1,n,1,n,1));
}
return 0;
}