线段树 + 懒标记 学习记录
C02【模板】线段树+懒标记 Luogu P3372 线段树——信息学竞赛算法_哔哩哔哩_bilibili
算法讲解110【扩展】线段树专题1-线段树原理和代码详解_哔哩哔哩_bilibili
线段树的作用
能够在O(logn)时间内 范围的维护,修改区间的某个状态
线段树的实现原理
n个数, 设m为区间的中点, 1~n区间的状态存在i位置, 1~m存在2 * i位置,m + 1~ n区间的状态存在2*i + 1的位置
存的数组开为4*n即可够用
代码实现(以区间和为例) (自己写的以后可能会优化)
初始化建立
void build(int p, int l, int r) { //l~r区间的状态存到p位置
if(l == r) {
sum[p] = a[l];
return sum[p];
}
int m = l + r >> 1;
int lc = p << 1, rc = p << 1 | 1;
sum[p] = build( lc, l, m);
sum[p] += build( rc, m + 1, r);
}
点修改
auto pl = [&](auto self, int p, int l, int r, int t, int x) -> void{
//t位置的数加上x
if(l == r && l == t){
sum[p] += x;
return;
}
int lc = 2 * p, rc = 2 * p + 1;
if((l + r >> 1) >= t) self(self, lc, l ,l + r >> 1, t, x);
else self(self, rc, (l + r >> 1) + 1, r, t ,x);
sum[p] = sum[lc] + sum[rc];
};
区间修改 (懒标记)
auto pl = [&](auto self, int p, int l, int r, int ll, int rr, int x) -> void{
if(l >= ll && r <= rr){
add[p] += x;
return;
}
int m = l + r >> 1;
/*写的时候丢了,debug很长时间*/sum[p] += (min(rr,r) - max(l,ll) + 1) * x;
int lc = 2 * p, rc = 2 * p + 1;
if(m >= ll) self(self, lc, l, m, ll, rr, x);
if(rr >= m + 1) self(self, rc,m + 1, r, ll, rr, x);
};
区间查询 (懒标记)
auto cha = [&](auto self, int p, int l, int r, int ll,int rr) -> void{
int m = l + r >> 1;
if(l >= ll && r <= rr){
ans += sum[p] + add[p] * (r - l + 1);
return;
}
int lc = 2 * p, rc = 2 * p + 1;
add[lc] += add[p], add[rc] += add[p];
/*丢了*/sum[p] += add[p] * (r - l + 1);
add[p] = 0;
if(ll <= m) self(self, lc, l ,m, ll, rr);
if(rr >= m + 1) self(self, rc, m + 1, r, ll, rr);
};
题目 : 洛谷 P3374 P3372 F-小红的数组操作_牛客周赛 Round 57 (nowcoder.com)