Daimayuan Online Judge 线段树打标记2
给
支持
- 1 l r d ,令所有的
加上 。 - 2 l r d ,令所有的
乘上 。 - 3 l r d ,令所有的
等于 。 - 4 l r ,查询
。
一:确定维护的信息,确定修改信息需要的标记。确定期间的合并。
- 信息需要区间值和
,区间大小 (维护和且区间加时必要)。 - 标记设计为
。不问为什么,问就是典。 - 合并:(以下默认模意义下)
- 信息与信息合并:
, 。 - 信息与标记合并:
- 标记与标记合并:
- 非常需要注意标记合并需要按照先后顺序,比如
与 分别为 与 ,显然不同。 。于是有 , 。
- 非常需要注意标记合并需要按照先后顺序,比如
- 信息与信息合并:
- 注意多个标记时的初始化,
,于是 时初始化 。
// 主要是确定 Info 和 Tag 的信息 struct Info { ll sum, sz; }; struct Tag { ll mul, add; }; struct Node { Info f; Tag t; } seg[N * 4]; // 确定他们的合并方式 Info operator + (const Info &l, const Info &r) { Info ret; ret = { ( l.sum + r.sum ) % mod, l.sz + r.sz }; return ret; } Info operator + (const Info &f, const Tag &t) { Info ret; ret = { ( ( f.sum * t.mul ) % mod + ( f.sz * t.add ) % mod ) % mod, f.sz }; return ret; } Tag operator + (const Tag &t1, const Tag &t2) { Tag ret; ret = { ( t1.mul * t2.mul ) % mod, ( t1.add * t2.mul + t2.add ) % mod }; return ret; } void update(int id) { seg[id].f = seg[ id * 2 ].f + seg[ id * 2 + 1].f; } void settag(int id, Tag t) { seg[id].f = seg[id].f + t; seg[id].t = seg[id].t + t; } void pushdown(int id) { if (seg[id].t.mul != 1 || seg[id].t.add != 0) { // 标记非空,一个习惯 settag( id * 2, seg[id].t ); settag( id * 2 + 1, seg[id].t ); seg[id].t = {1, 0}; } }
只需要推理出
然后改一下
注意
view
#include <bits/stdc++.h> typedef long long ll; const int N = 200005; const int mod = 1E9 + 7; int a[N]; struct Info { ll sum, sz; }; struct Tag { ll mul, add; }; struct Node { Info f; Tag t; } seg[N * 4]; Info operator + (const Info &l, const Info &r) { Info ret; ret = { ( l.sum + r.sum ) % mod, l.sz + r.sz }; return ret; } Info operator + (const Info &f, const Tag &t) { Info ret; ret = { ( ( f.sum * t.mul ) % mod + ( f.sz * t.add ) % mod ) % mod, f.sz }; return ret; } Tag operator + (const Tag &t1, const Tag &t2) { Tag ret; ret = { ( t1.mul * t2.mul ) % mod, ( t1.add * t2.mul + t2.add ) % mod }; return ret; } void update(int id) { seg[id].f = seg[ id * 2 ].f + seg[ id * 2 + 1].f; } void settag(int id, Tag t) { seg[id].f = seg[id].f + t; seg[id].t = seg[id].t + t; } void pushdown(int id) { if (seg[id].t.mul != 1 || seg[id].t.add != 0) { // 标记非空,一个习惯 settag( id * 2, seg[id].t ); settag( id * 2 + 1, seg[id].t ); seg[id].t = {1, 0}; } } void build(int id, int l, int r) { seg[id].t = {1, 0}; if (l == r) { seg[id].f = {a[l], 1}; } else { int mid = ( l + r ) >> 1; build( id * 2, l, mid ); build( id * 2 + 1, mid + 1, r ); update(id); } } Info query(int id, int l, int r, int ql, int qr) { if (l == ql && r == qr) { return seg[id].f; } else { pushdown(id); int mid = ( l + r ) >> 1; if ( qr <= mid ) return query( id * 2, l, mid, ql, qr ); else if ( ql > mid ) return query( id * 2 + 1, mid + 1, r, ql, qr ); else return query( id * 2, l, mid, ql, mid ) + query( id * 2 + 1, mid + 1, r, mid + 1, qr); } } void modify(int id, int l, int r, int ql, int qr, Tag t) { if (l == ql && r == qr) { settag( id, t ); } else { pushdown(id); int mid = ( l + r ) >> 1; if ( qr <= mid ) modify( id * 2, l, mid, ql, qr, t ); else if ( ql > mid) modify( id * 2 + 1, mid + 1, r, ql, qr, t ); else modify( id * 2, l, mid, ql, mid, t ), modify( id * 2 + 1, mid + 1, r, mid + 1, qr, t ); update(id); } } int main() { int n, q; std::cin >> n >> q; for (int i = 1; i <= n; i++) std::cin >> a[i]; build(1, 1, n); for (int i = 1; i <= q; i++) { int typ; std::cin >> typ; if ( typ == 1 ) { int l, r, d; std::cin >> l >> r >> d; modify(1, 1, n, l, r, {1, d}); } else if ( typ == 2 ) { int l, r, d; std::cin >> l >> r >> d; modify(1, 1, n, l, r, {d, 0}); } else if ( typ == 3 ) { int l, r, d; std::cin >> l >> r >> d; modify(1, 1, n, l, r, {0, d}); } else { int l, r; std::cin >> l >> r; auto ans = query(1, 1, n, l, r); std::cout << ans.sum << '\n'; } } return 0; }
——永远是挑战而不是练习,下次一定更好。
分类:
数据结构 / 线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】