线段树多懒标记
最近在思考:如何对一个序列维护带有两种区间修改的多查询问题。这样不可避免地需要对两种修改操作分别维护一种懒标记。但显然,不能将两种懒标记独立看待,因为对于两种操作,先后顺序不同会造成不同的影响。因此如何处理两个懒标记之间的相互影响至关重要, \(pushdown\) 函数需要精心设计。
这里口胡两种情况(不一定对),阐述一下设计懒标记的原理。
区间加与区间乘
考虑两种操作的先后顺序:
- 先乘后加:直接进行即可
- 先加后乘:加的部分也需要乘,再作和
void pushdown(int p){
if(tr[p].add == 0 && tr[p].mul == 1) return;
tr[lc].sum = (tr[lc].sum * tr[p].mul) + tr[p].add * (tr[lc].r - tr[lc].l + 1);
tr[rc].sum = (tr[rc].sum * tr[p].mul) + tr[p].add * (tr[rc].r - tr[rc].l + 1);
// 先处理乘法懒标记,再处理加法懒标记
tr[lc].mul = tr[lc].mul * tr[p].mul;
tr[rc].mul = tr[rc].mul * tr[p].mul;
tr[lc].add = tr[lc].add * tr[p].mul + tr[p].add;
tr[rc].add = tr[rc].add * tr[p].mul + tr[p].add;
tr[p].add = 0;
tr[p].mul = 1;
}
区间加与区间赋值 (查询区间最大值)
// max
template<typename T>
struct SegTree
{
struct Node
{
int l, r;
T maxv, tag_fix, tag_add;
}tr[maxn << 2];
#define lc p<<1
#define rc p<<1|1
void pushup(int p)
{
tr[p].maxv = max(tr[lc].maxv, tr[rc].maxv);
}
void pushdown(int p)
{
if(tr[p].tag_fix != -1){
tr[lc].maxv = tr[rc].maxv = tr[p].tag_fix;
}
if(tr[p].tag_add){
tr[lc].maxv += tr[p].tag_add;
tr[rc].maxv += tr[p].tag_add;
}
if(tr[p].tag_fix != -1){
tr[lc].tag_fix = tr[rc].tag_fix = tr[p].tag_fix;
tr[lc].tag_add = tr[rc].tag_add = 0;
}
if(tr[p].tag_add){
tr[lc].tag_add += tr[p].tag_add;
tr[rc].tag_add += tr[p].tag_add;
}
tr[p].tag_fix = -1;
tr[p].tag_add = 0;
}
void build(int p, int l, int r,auto& arr)
{
tr[p] = { l,r,arr[l],-1,0};
if (l == r) return;
int mid = l + r >> 1;
build(lc, l, mid , arr);
build(rc, mid + 1, r , arr);
pushup(p);
}
void update_fix(int p, int l, int r, T k)
{
if (l <= tr[p].l && tr[p].r <= r)
{
tr[p].maxv = k;
tr[p].tag_fix = k;
tr[p].tag_add = 0;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
pushdown(p);
if (l <= mid) update_fix(lc, l ,r, k);
if (r > mid) update_fix(rc, l ,r, k);
pushup(p);
}
void update_add(int p, int l, int r, T k)
{
if (l <= tr[p].l && tr[p].r <= r)
{
tr[p].maxv += k;
tr[p].tag_add += k;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
pushdown(p);
if (l <= mid) update_add(lc, l ,r, k);
if (r > mid) update_add(rc, l ,r, k);
pushup(p);
}
T querymax(int p, int l, int r)
{
if (l <= tr[p].l && tr[p].r <= r) return tr[p].maxv;
pushdown(p);
int mid = tr[p].l + tr[p].r >> 1;
T maxv = INT_MIN;
if (l <= mid) maxv = max(maxv, querymax(lc, l, r));
if (r > mid) maxv = max(maxv, querymax(rc, l, r));
return maxv;
}
};

浙公网安备 33010602011771号