您的位置: 首页> 滚动 > > 正文

视焦点讯!「学习笔记」线段树标记永久化

2023-05-17 22:31:42 来源:博客园

第一次见到这个词是在 zkw 线段树的课件里见到的。


(资料图片)

标记永久化可以避免下传懒惰标记,只需在进行询问时把标记的影响加到答案当中,从而降低程序常数。

洛谷的模板题也证明,确实是小常数。这三次提交都是递归写法,如果搭配 zkw 线段树,应该会跑得更快。

具体操作

我们在讲懒标向下递归的过程中,如果当前区间正好等于查询区间,那就直接改懒标和数值,倘若当前区间包含查询区间但不与查询区间相等,那我们只修改值,这些操作与线段树修改操作很像。

inline void modify(int u, int l, int r, int lr, int rr, ll c) {t[u].val += (rr - lr + 1) * c;if (lr == l && r == rr) {t[u].laz += c;return ;}if (rr <= mid)modify(ls, l, mid, lr, rr, c);else if (lr > mid)modify(rs, mid + 1, r, lr, rr, c);else {modify(ls, l, mid, lr, mid, c);modify(rs, mid + 1, r, mid + 1, rr, c);}}

需要注意的是,如果查询的区间横跨左右两个孩子区间,那我们需要将查询区间也从 mid处分开。

设置好懒标,查询时该如何处理懒标呢?按照一般的写法,在向下递归时,我们还要用递归把懒标也一起向下传递,而标记永久化则是舍弃了向下传递懒标这个操作,我们在查询时设置一个值,用它来记录沿路的懒标,最后一起统计即可。为什么要记录沿路的懒标呢?如果包含该区间的大区间被打上了懒标,则说明这一整个大区间都受到这个懒标的影响,所以把它记录下来。

inline ll query(int u, int l, int r, int lr, int rr, ll add) {if (lr == l && r == rr) {return t[u].val + add * t[u].len;}ll sum = 0;if (rr <= mid) {sum = query(ls, l, mid, lr, rr, add + t[u].laz);}else if (lr > mid) {sum = query(rs, mid + 1, r, lr, rr, add + t[u].laz);}else {sum = query(ls, l, mid, lr, mid, add + t[u].laz) + query(rs, mid + 1, r, mid + 1, rr, add + t[u].laz);}return sum;}

最后处理答案时,就是将懒标的和乘上这个区间的长度,add记录的是懒标和,可以将这个 add看作是对于这个区间的每个元素一共要增加的值。

总结

好处:

码量小,不用写 pushdownpushup。在可持久化线段树上应用该技巧能做到区间修改的效果。

坏处:

适用范围有限,只有当求的东西满足区间贡献独立。比如区间加法。区间最大值就无法标记永久化。多标记好像也不适用。

总归来说,对于一般的线段树,递归写法就足够了,标记永久化用的较少,对于线段树套线段树这样的应该会用的比较多。

例题

【模板】线段树 1

#include using namespace std;typedef long long ll;#define ls (u << 1)#define rs (u << 1 | 1)#define mid ((l + r) >> 1)const int N = 1e5 + 5;int n, m;struct seg_tree {int len;ll val, laz;} t[N << 2];inline void build(int u, int l, int r) {t[u].len = r - l + 1, t[u].laz = 0;if (l == r) {cin >> t[u].val;return ;}build(ls, l, mid);build(rs, mid + 1, r);t[u].val = t[ls].val + t[rs].val;}inline void modify(int u, int l, int r, int lr, int rr, ll c) {t[u].val += (rr - lr + 1) * c;if (lr == l && r == rr) {t[u].laz += c;return ;}if (rr <= mid)modify(ls, l, mid, lr, rr, c);else if (lr > mid)modify(rs, mid + 1, r, lr, rr, c);else {modify(ls, l, mid, lr, mid, c);modify(rs, mid + 1, r, mid + 1, rr, c);}}inline ll query(int u, int l, int r, int lr, int rr, ll add) {if (lr == l && r == rr) {return t[u].val + add * t[u].len;}ll sum = 0;if (rr <= mid) {sum = query(ls, l, mid, lr, rr, add + t[u].laz);}else if (lr > mid) {sum = query(rs, mid + 1, r, lr, rr, add + t[u].laz);}else {sum = query(ls, l, mid, lr, mid, add + t[u].laz) + query(rs, mid + 1, r, mid + 1, rr, add + t[u].laz);}return sum;}int main() {ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);cin >> n >> m;build(1, 1, n);for (int i = 1, op, x, y; i <= m; ++ i) {cin >> op >> x >> y;if (op == 1) {ll k;cin >> k;modify(1, 1, n, x, y, k);}else {cout << query(1, 1, n, x, y, 0) << "\n";}}return 0;}

标签:

下一篇: “遇见”西安_感受魅力_全球报资讯
上一篇: 全球看点:如何挖空鸡蛋_给小女孩子送什么礼物好一点

元宵假期旅游市场热度高涨

春节假期旅游消费市场余韵未消,元宵节假期接踵而至。恰逢周末,不...

快看:北京牌照字母代表(北京牌电视机)

【资料图】您好,现在渔夫来为大家解答以上的问题。北京牌照字母代表...

当前速讯:索太集成灶怎么样(索太集成灶怎么样)

您好,现在渔夫来为大家解答以上的问题。索太集成灶怎么样,索太集成...

环球观焦点:结膜炎一般几天能消肿(结膜炎一般几天才能好)

您好,现在渔夫来为大家解答以上的问题。结膜炎一般几天能消肿,结膜...
资讯推荐:雪莲果是寒性还是凉性(雪莲果是寒性水果)
您好,现在渔夫来为大家解答以上的问题。雪莲果是寒性还是凉性,雪莲...
世界热点!抖音纯音乐噔噔噔钢琴(抖音纯音乐噔噔噔)
(资料图片仅供参考)您好,现在渔夫来为大家解答以上的问题。抖音纯音...
热消息:都在聊不确定性,物联网企业如何找到“确定性”?
进入2022年,全球变化的因素开始增多,我们迫切需要在这个不确定的...
世界热点!智能网联汽车正在成为全球汽车创新发展的引领者
(相关资料图)智能网联汽车是指车联网和智能汽车的有机结合。它是新...
世界热点!工信部:我国5G基站总数已达225万个
(资料图片仅供参考)近日,工信部发布《2022年1-10月份通信业经济运...
环球最资讯丨中建三局都下场,建筑机器人正在彻出一个万亿市场
随着大基建及房地产的黄金发展期过去,寻求更高质量的运营模式必然...