0%

身败名裂线段树

最近在讲课的时候,竟然连续WA了一道线段树的题,一番debug下来才意识到自己犯了和很久之前一样的错误

个人习惯:打上lazy标记表示此区间内(包含此节点)的数据未更新。

修改时:直接返回要下放,查询子区间要下放,pushup前要将子区间的标记也下放。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void update(int x, int l, int r, int ql, int qr, const Mat &k) {
if (ql <= l && r <= qr) {
laz[x] *= k; // 打上lazy标记
down(x);// 立即下放标记
return;
}
down(x);// 更新子区间前先下放标记
gm;
if (ql <= mid) update(ls, l, mid, ql, qr, k);
else down(ls);
if (mid < qr) update(rs, mid + 1, r, ql, qr, k);
else down(rs);
// 注意,因为之后要pushup,所以左右区间都要正确更新,即,每个区间如果不访问,要特地pushdown一下,这样pushup结果才能对;
up(x);
}

注意,对于标记互相冲突(有先后顺序的标记),应该在进入节点时先pushdown一遍。

另外,在pushup时,一定要判断rs是否超过了线段树数组M的范围,不然就要开8倍的空间。这是因为有时候会pushdown叶子节点。

1
2
3
4
5
6
7
8
9
10
il void down(int x, int len)
{
if(laz[x]) {
sum[x] += laz[x] * len;
if(rs < M) {
laz[ls] += laz[x], laz[rs] += laz[x];
}
laz[x] = 0;
}
}