/*
translation:
有一段数列,初始值为1,后来有若干操作,把连续一段的数字改成1,2,3中的某一个。问经过若干操作后
这段数列的和是多少?
solution:
线段树的区间操作。
note:
注意这道题和poj3468的不同是poj3468的操作顺序对结果没有影响,而这道题是有影响的。
所以懒惰标记无论在更新还是查询的时候都要往下面带。
date:
2016.11.18
*/
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 100000 + 5;
int n, q;
int s[maxn*4], e[maxn*4]; //线段树保存的节点的和
int sum[maxn*4], tag[maxn*4];
void push_up(int o)
{
sum[o] = sum[o << 1] + sum[o << 1 | 1];
}
void push_down(int o, int num)
{
if(tag[o]){
tag[o << 1] = tag[o];
tag[o << 1 | 1] = tag[o];
sum[o << 1] = tag[o] * (num - (num >> 1));
sum[o << 1 | 1] = tag[o] * (num >> 1);
tag[o] = 0;
}
}
void build_tree(int l, int r, int o)
{
s[o] = l;
e[o] = r;
tag[o] = 0;
if(l == r){
sum[o] = 1;
return;
}
build_tree(l, (l + r) / 2, o << 1);
build_tree((l + r) / 2 + 1, r, o << 1 | 1);
push_up(o);
}
void update(int d, int l, int r, int o) //将o节点内所有元素改成d
{
if(s[o] == l && e[o] == r){
tag[o] = d;
sum[o] = d * (r - l + 1);
return;
}
if(s[o] == e[o]) return;
push_down(o, (e[o] - s[o] + 1));
int m = (s[o] + e[o]) / 2;
if(r <= m) update(d, l, r, o << 1);
else if(l > m) update(d, l, r, o << 1 | 1);
else{
update(d, l, m, o << 1);
update(d, m + 1, r, o << 1 | 1);
}
push_up(o);
}
int query(int l, int r, int o)
{
if(s[o] == l && e[o] == r){
return sum[o];
}
push_down(0, e[o] - s[o] + 1);
int res = 0;
int m = (s[o] + e[o]) / 2;
if(r <= m) res += query(l, r, o << 1);
else if(l > m) res += query(l, r, o << 1 | 1);
else{
res += query(l, m, o << 1);
res += query(m + 1, r, o << 1 | 1);
}
return res;
}
int main()
{
//freopen("in.txt", "r", stdin);
int T, kase = 0;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
build_tree(1, n, 1);
int x, y, z;
scanf("%d", &q);
while(q--){
scanf("%d%d%d", &x, &y, &z);
update(z, x, y, 1);
}
printf("Case %d: The total value of the hook is %d.\n", ++kase, query(1, n, 1));
}
return 0;
}
hdu1698(线段树区间操作,绝对懒惰标记)
最新推荐文章于 2022-11-30 09:59:26 发布