数据结构——线段树 例题及代码
数据结构——线段树 入门以后 学习笔记
入门笔记有时间写。
才发现我不会线段树。/ll
可以看出来我很喜欢 class
/cf
有的代码需要前置:
using ll = long long; constexpr ll mod = 998244353; constexpr int root = 1;
P3372 线段树 1
class seg_t { private: struct emm { int l, r; ll v, lz; }; int n; vector<emm> a; void pushup(int k) { a[k].v = a[k * 2].v + a[k * 2 + 1].v; } void run(int k, ll v) { a[k].lz += v; a[k].v += v * (a[k].r - a[k].l + 1); } void pushdown(int k) { if (!a[k].lz) return; run(k * 2, a[k].lz); run(k * 2 + 1, a[k].lz); a[k].lz = 0; } void build(vector<ll> &q, int k, int l, int r) { a[k].lz = 0, a[k].l = l, a[k].r = r; if (l == r) { a[k].v = q[l]; return; } int mid = l + (r - l >> 1); build(q, k * 2, l, mid); build(q, k * 2 + 1, mid + 1, r); pushup(k); } void modify(int k, const int p, const int q, const ll v) { auto &l = a[k].l, &r = a[k].r; if (l >= p && r <= q) { run(k, v); return; } pushdown(k); int mid = l + (r - l >> 1); if (mid >= p) modify(k * 2, p, q, v); if (mid + 1 <= q) modify(k * 2 + 1, p, q, v); pushup(k); } ll query(int k, const int p, const int q) { auto &l = a[k].l, &r = a[k].r; if (l >= p && r <= q) return a[k].v; pushdown(k); int mid = l + (r - l >> 1); ll res = 0; if (mid >= p) res += query(k * 2, p, q); if (mid + 1 <= q) res += query(k * 2 + 1, p, q); return res; } public: seg_t(vector<ll> &q) { n = q.size(), a.resize(4 * n); build(q, 1, 1, n); } void add(int l, int r, ll v) { modify(1, l, r, v); } ll sum(int l, int r) { return query(1, l, r); } };
P3373 线段树 2
class seg_t { private: struct emm { int l, r; ll v, ad, ml; }; int n; vector<emm> a; void push_up(int k) { (a[k].v = a[k * 2].v + a[k * 2 + 1].v) %= mod; } void action_add(int k, ll t) { (a[k].ad += t) %= mod; (a[k].v += t * (a[k].r - a[k].l + 1) % mod) %= mod; } void action_mul(int k, ll t) { (a[k].v *= t) %= mod; (a[k].ad *= t) %= mod, (a[k].ml *= t) %= mod; } void push_down(int k) { if (a[k].ml != 1) { action_mul(k * 2, a[k].ml); action_mul(k * 2 + 1, a[k].ml); a[k].ml = 1; } if (a[k].ad) { action_add(k * 2, a[k].ad); action_add(k * 2 + 1, a[k].ad); a[k].ad = 0; } } void build(vector<ll> &q, int k, int l, int r) { a[k].l = l, a[k].r = r; a[k].ad = 0, a[k].ml = 1; if (l == r) { a[k].v = q[l]; return; } int mid = l + (r - l >> 1); build(q, k * 2, l, mid); build(q, k * 2 + 1, mid + 1, r); push_up(k); } ll query(int k, int p, int q) { auto &l = a[k].l, &r = a[k].r; if (l >= p && r <= q) return a[k].v; push_down(k); int mid = l + (r - l >> 1); ll res = 0; if (mid >= p) res += query(k * 2, p, q); if (mid + 1 <= q) res += query(k * 2 + 1, p, q); return res % mod; } void modify_add(int k, int p, int q, ll v) { auto &l = a[k].l, &r = a[k].r; if (l >= p && r <= q) { action_add(k, v); return; } push_down(k); int mid = l + (r - l >> 1); if (mid >= p) modify_add(k * 2, p, q, v); if (mid + 1 <= q) modify_add(k * 2 + 1, p, q, v); push_up(k); } void modify_mul(int k, int p, int q, ll v) { auto &l = a[k].l, &r = a[k].r; if (l >= p && r <= q) { action_mul(k, v); return; } push_down(k); int mid = l + (r - l >> 1); if (mid >= p) modify_mul(k * 2, p, q, v); if (mid + 1 <= q) modify_mul(k * 2 + 1, p, q, v); push_up(k); } public: seg_t(vector<ll> &q) { n = q.size(); a.resize(n * 4); build(q, root, 1, n); } ll sum(int l, int r) { return query(root, l, r); } void add(int l, int r, ll v) { modify_add(root, l, r, v); } void mul(int l, int r, ll v) { modify_mul(root, l, r, v); } };
CF438D The Child and Sequence
取模的两个定理。一个是不取模,一个是取了小于一半。
class seg_t { private: struct emm { int l, r; ll v, mx; }; int n; vector<emm> a; void push_up(int k) { a[k].v = a[k * 2].v + a[k * 2 + 1].v; a[k].mx = max(a[k * 2].mx, a[k * 2 + 1].mx); } void build(vector<ll> &q, int k, int l, int r) { a[k].l = l, a[k].r = r; if (l == r) { a[k].v = a[k].mx = q[l]; return; } int mid = l + (r - l >> 1); build(q, k * 2, l, mid); build(q, k * 2 + 1, mid + 1, r); push_up(k); } ll query(int k, int p, int q) { auto &l = a[k].l, &r = a[k].r; if (l >= p && r <= q) return a[k].v; int mid = l + (r - l >> 1); ll res = 0; if (mid >= p) res += query(k * 2, p, q); if (mid + 1 <= q) res += query(k * 2 + 1, p, q); return res; } void modify(int k, int x, ll v) { auto &l = a[k].l, &r = a[k].r; if (l == r) { a[k].v = a[k].mx = v; return; } int mid = l + (r - l >> 1); if (x <= mid) modify(k * 2, x, v); else modify(k * 2 + 1, x, v); push_up(k); } void putmod(int k, int p, int q, ll m) { auto &l = a[k].l, &r = a[k].r; if (l == r) { a[k].v = a[k].mx = a[k].v % m; return; } int mid = l + (r - l >> 1); if (mid >= p && a[k * 2].mx >= m) putmod(k * 2, p, q, m); if (mid + 1 <= q && a[k * 2 + 1].mx >= m) putmod(k * 2 + 1, p, q, m); push_up(k); } public: seg_t(vector<ll> &q) { n = q.size(); a.resize(n * 4); build(q, root, 1, n); } ll sum(int l, int r) { return query(root, l, r); } void mod(int l, int r, ll x) { putmod(root, l, r, x); } void change(int k, ll x) { modify(root, k, x); } };
SP1043 GSS1 & SP1716 GSS3 & SP2916 GSS5
class seg_t { private: struct v_t { int prefix, suffix; int sum, res; void set(const int x) { prefix = suffix = sum = res = x; } friend v_t operator+ (const v_t &a, const v_t &b) { v_t res; res.sum = a.sum + b.sum; res.prefix = max(a.prefix, a.sum + b.prefix); res.suffix = max(b.suffix, b.sum + a.suffix); res.res = max(max(a.res, b.res), a.suffix + b.prefix); return res; } }; struct emm { int l, r; v_t v; }; int n; vector<emm> a; void push_up(int k) { a[k].v = a[k * 2].v + a[k * 2 + 1].v; } void build(vector<int> &q, int k, int l, int r) { a[k].l = l, a[k].r = r; if (l == r) { a[k].v.set(q[l]); return; } int mid = l + (r - l >> 1); build(q, k * 2, l, mid); build(q, k * 2 + 1, mid + 1, r); push_up(k); } void modify(int k, int x, int v) { auto &l = a[k].l, &r = a[k].r; if (l == r) { a[k].v.set(v); return; } int mid = l + (r - l >> 1); if (x <= mid) modify(k * 2, x, v); else modify(k * 2 + 1, x, v); push_up(k); } v_t query(int k, int p, int q) { auto &l = a[k].l, &r = a[k].r; if (l >= p && r <= q) return a[k].v; int mid = l + (r - l >> 1); if (mid < p) return query(k * 2 + 1, p, q); if (mid + 1 > q) return query(k * 2, p, q); return query(k * 2, p, q) + query(k * 2 + 1, p, q); } public: seg_t(vector<int> &q) { n = q.size(); a.resize(4 * n); build(q, root, 1, n); } int mis(int l, int r) { return query(root, l, r).res; } int sum(int l, int r) { return query(root, l, r).sum; } int pre(int l, int r) { return query(root, l, r).prefix; } int suf(int l, int r) { return query(root, l, r).suffix; } void change(int x, int v) { modify(root, x, v); } }; void solve(int n) { vector<int> a(n + 1); rep(i, n) a[i + 1] = rr; int m = ur; seg_t seg(a); auto query = [&] (int l1, int r1, int l2, int r2) { if (l1 == r1 && r1 == r2) return seg.mis(l1, r2); if (r1 < l2) return seg.sum(r1 + 1, l2 - 1) + seg.suf(l1, r1) + seg.pre(l2, r2); int ans = seg.mis(l2, r1); if(l1 < l2) ans = max(ans, seg.suf(l1, l2) + seg.pre(l2, r2) - a[l2]); if(r2 > r1) ans = max(ans, seg.suf(l1, r1) + seg.pre(r1, r2) - a[r1]); return ans; }; while (m--) { int l1 = ur, r1 = ur, l2 = ur, r2 = ur; printf("%d\n", query(l1, r1, l2, r2)); } }
P1253 扶苏的问题
曾经写的代码。和现在的线段树风格不一样。
template<typename tp, tp INIT> class segment { #define mid ((l + r) >> 1) #define vp vector<tp> private: int n; vp s, mad, mre; void _build(int k, int l, int r, vp &a) { if (l == r) { s[k] = a[l]; return; } _build(k * 2, l, mid, a), _build(k * 2 + 1, mid + 1, r, a); s[k] = max(s[k * 2], s[k * 2 + 1]); } void _addmad(int k, tp x) { s[k] += x; if (mad[k] == -INIT) mad[k] = x; else mad[k] += x; } void _addmre(int k, tp x) { s[k] = mre[k] = x, mad[k] = -INIT; } void _pushdown(int k) { if (mre[k] != -INIT) _addmre(k * 2, mre[k]), _addmre(k * 2 + 1, mre[k]), mre[k] = -INIT; if (mad[k] != -INIT) _addmad(k * 2, mad[k]), _addmad(k * 2 + 1, mad[k]), mad[k] = -INIT; } void _add(int k, int l, int r, int p, int q, tp x) { if (r < p || l > q) return; if (l >= p && r <= q) { _addmad(k, x); return; } _pushdown(k); _add(k * 2, l, mid, p, q, x), _add(k * 2 + 1, mid + 1, r, p, q, x); s[k] = max(s[k * 2], s[k * 2 + 1]); } void _modify(int k, int l, int r, int p, int q, tp x) { if (r < p || l > q) return; if (l >= p && r <= q) { _addmre(k, x); return; } _pushdown(k); _modify(k * 2, l, mid, p, q, x), _modify(k * 2 + 1, mid + 1, r, p, q, x); s[k] = max(s[k * 2], s[k * 2 + 1]); } tp _query(int k, int l, int r, int p, int q) { if (l >= p && r <= q) return s[k]; _pushdown(k); if (mid < p) return _query(k * 2 + 1, mid + 1, r, p, q); if (mid >= q) return _query(k * 2, l, mid, p, q); return max(_query(k * 2 + 1, mid + 1, r, p, q), _query(k * 2, l, mid, p, q)); } public: void build(vp &a) { n = (int)a.size() - 1, s = mad = mre = vp(3 * n, -INIT), _build(1, 1, n, a); } void add(int l, int r, tp x) { _add(1, 1, n, l, r, x); } void modify(int l, int r, tp x) { _modify(1, 1, n, l, r, x); } tp query(int l, int r) { return _query(1, 1, n, l, r); } #undef mid #undef vp };
本文来自博客园,作者:RainPPR,转载请注明原文链接:https://www.cnblogs.com/RainPPR/p/17974548/segment-tree-2
如有侵权请联系我(或 2125773894@qq.com)删除。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战