http://acm.hdu.edu.cn/showproblem.php?pid=1698
线段树成段更新,这里用到了懒惰标记,简单说一下。
单点更新只是针对一个点,所以改了该点即可。但是成段更新一旦改一个区间,那么其所支配的节点都要更改,这样复杂度就增加。为了避免这种情况,懒惰标记就产生了。他只给对应的线段节点赋值,其下节点都不改变。但是当这个节点不是所查找的线段时,就会把自身价值传递给儿子们,再将自己变为-1(意思是这个节点没价值了)。这样继续进行查找时也就直接通过这个节点,通向儿子去了。从这方面讲,复杂度也提升不了多少,当遇到更新操作少、查询操作多的样例时,标记都会回归最底层,懒惰标记也就没用武之地了。不过优化总归优化,整体性能还是提升了不少的。
再有就是成段标记了,思想比较好懂,只是更行时因为成段,区间要拆分。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 100010;
const int INF = 1e8;
struct line
{
int l;
int r;
int value;
}tree[4 * N];
int a[N];
void build(int i, int l, int r)
{
tree[i].l = l;
tree[i].r = r;
tree[i].value = 1;
if(l == r) return;
int mid = (l + r) >> 1;
build(i*2, l, mid);
build(i*2+1, mid+1, r);
}
int query(int i, int l, int r)
{
if(tree[i].value != -1)
{
return (tree[i].value * (r - l + 1));
}
int mid = (tree[i].l + tree[i].r) >> 1;
if(mid >= r) return query(i*2, l, r);
else if(mid < l) return query(i*2+1, l, r);
else return (query(i*2, l, mid) + query(i*2+1, mid+1, r));
}
void update(int i, int l, int r, int val)
{
if(tree[i].l == l && tree[i].r == r)
{
tree[i].value = val;
return;
}
if(tree[i].value != -1)//已经搜索到这一点了但没有执行上个条件就说明不是想要的结果,这个节点就没有价值了,将价值传到子节点
{
tree[i*2].value = tree[i].value;
tree[i*2+1].value = tree[i].value;
tree[i].value = -1;
}
int mid = (tree[i].l + tree[i].r) >> 1;
if(mid >= r) update(i*2, l, r, val);
else if(mid < l) update(i*2+1, l, r, val);
else
{
update(i*2, l, mid, val);
update(i*2+1, mid+1, r, val);
}
}
int main()
{
// freopen("in.txt", "r", stdin);
int num, n, t, q, Case = 1, l, r, val;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
build(1, 1, n);
scanf("%d", &q);
for(int i = 0; i < q; i++)
{
scanf("%d%d%d", &l, &r, &val);
update(1, l, r, val);
}
printf("Case %d: The total value of the hook is %d.\n", Case++, query(1, 1, n));
}
return 0;
}