1 条题解
-
0
单侧递归线段树能高效维护前后缀最值有关的信息。
显然 操作影响的是前缀最大值位置。
建立线段树,每个节点维护 的最大值 ,前缀最大值个数 , 的和 。
考虑 pushup, 可以直接用,但对于 需要满足值 才行,考虑递归下去。设当前到 ,若 ,则递归 ,否则递归 并加上 中值 的部分,即 。
对于 操作,考虑维护标记 ,apply 时更新 中 的位置,pushdown 时下放到 。这个不能简单 apply,类似上面的方法递归下去即可。执行 操作时维护当前前缀最大值 ,对于拆出的 个区间递归即可。
对于 操作,再维护一个标记 即可,递归时要下传 ,不影响复杂度。
显然单次递归是 的,复杂度为 。
::::info[code]
#include <bits/stdc++.h> using namespace std; using i64 = long long; using ui64 = unsigned long long; using i128 = __int128; using ui128 = unsigned __int128; using f4 = float; using f8 = double; using f16 = long double; template<class T> bool chmax(T &a, const T &b){ if(a < b){ a = b; return true; } return false; } template<class T> bool chmin(T &a, const T &b){ if(a > b){ a = b; return true; } return false; } #define ls (u << 1) #define rs (u << 1 | 1) struct SGT { struct Node { i64 mx, cmx, sum, add, tag; }; int n; vector<Node> tr; void pull(int u, int l, int r) { int mid = (l + r) >> 1; tr[u].mx = max(tr[ls].mx, tr[rs].mx); tr[u].sum = tr[ls].sum + tr[rs].sum; tr[u].cmx = tr[ls].cmx + calc(rs, mid + 1, r, tr[ls].mx); } void pushadd(int u, i64 v) { tr[u].mx += v, tr[u].add += v; } void pushtag(int u, int l, int r, i64 mx, i64 v) { if (tr[u].mx <= mx) return; if (l == r) { tr[u].sum += v * tr[u].cmx, tr[u].tag += v; return; } if (tr[u].add) { pushadd(ls, tr[u].add); pushadd(rs, tr[u].add); tr[u].add = 0; } int mid = (l + r) >> 1; if (tr[ls].mx <= mx) { i64 lst = tr[rs].sum; pushtag(rs, mid + 1, r, mx, v); tr[u].sum += tr[rs].sum - lst; } else { tr[u].tag += v, tr[u].sum += v * (tr[u].cmx - tr[ls].cmx); i64 lst = tr[ls].sum; pushtag(ls, l, mid, mx, v); tr[u].sum += tr[ls].sum - lst; } } void push(int u, int l, int r) { int mid = (l + r) >> 1; if (tr[u].add) { pushadd(ls, tr[u].add); pushadd(rs, tr[u].add); tr[u].add = 0; } if (tr[u].tag) { pushtag(rs, mid + 1, r, tr[ls].mx, tr[u].tag); tr[u].tag = 0; } } void build(int u, int l, int r, const vector<int>& h) { if (l == r) { tr[u].mx = h[l]; tr[u].cmx = 1; return; } int mid = (l + r) >> 1; build(ls, l, mid, h); build(rs, mid + 1, r, h); pull(u, l, r); } i64 calc(int u, int l, int r, i64 mx) { if (tr[u].mx <= mx) return 0; if (l == r) return 1; if (tr[u].add) { pushadd(ls, tr[u].add); pushadd(rs, tr[u].add); tr[u].add = 0; } int mid = (l + r) >> 1; if (tr[ls].mx <= mx) return calc(rs, mid + 1, r, mx); else return calc(ls, l, mid, mx) + tr[u].cmx - tr[ls].cmx; } void addh(int u, int l, int r, int L, int R, i64 v) { if (r < L || R < l) return; if (L <= l && r <= R) { pushadd(u, v); return; } int mid = (l + r) >> 1; push(u, l, r); addh(ls, l, mid, L, R, v); addh(rs, mid + 1, r, L, R, v); pull(u, l, r); } void add(int u, int l, int r, int L, int R, i64 &mx) { if (r < L || R < l) return; if (L <= l && r <= R) { pushtag(u, l, r, mx, 1); chmax(mx, tr[u].mx); return; } int mid = (l + r) >> 1; push(u, l, r); add(ls, l, mid, L, R, mx); add(rs, mid + 1, r, L, R, mx); pull(u, l, r); } i64 ask(int u, int l, int r, int L, int R) { if (r < L || R < l) return 0; if (L <= l && r <= R) return tr[u].sum; int mid = (l + r) >> 1; push(u, l, r); return ask(ls, l, mid, L, R) + ask(rs, mid + 1, r, L, R); } i64 get(int u, int l, int r, int x) { if (l == r) return tr[u].mx; int mid = (l + r) >> 1; push(u, l, r); if (x <= mid) return get(ls, l, mid, x); else return get(rs, mid + 1, r, x); } void addh(int l, int r, i64 v) { addh(1, 0, n - 1, l, r, v); } void add(int l, int r, i64 &mx) { add(1, 0, n - 1, l, r, mx); } i64 ask(int l, int r) { return ask(1, 0, n - 1, l, r); } i64 get(int x) { return get(1, 0, n - 1, x); } void init(const vector<int>& h) { n = (int)h.size(); tr.assign(n << 2, {}); build(1, 0, n - 1, h); } } seg; vector<i64> tower_events(vector<int> H, vector<vector<int>> E) { int n = (int)H.size(); seg.init(H); vector<i64> ans; for (auto e : E) { if (e.size() == 1) { int x = e[0]; i64 mx = seg.get(x); seg.add(x + 1, n - 1, mx); } if (e.size() == 2) { int l = e[0], r = e[1]; ans.push_back(seg.ask(l, r)); } if (e.size() == 3) { int l = e[0], r = e[1], v = e[2]; seg.addh(l, r, v); } } return ans; } signed main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int n, q; cin >> n >> q; vector<int> H(n); for (int i = 0; i < n; i++) cin >> H[i]; vector<vector<int>> E(q); for (int i = 0, t; i < q; i++) { cin >> t, E[i].resize(t); for (auto &x : E[i]) cin >> x; } auto ans = tower_events(H, E); for (auto x : ans) cout << x << '\n'; return 0; }
- 1
信息
- ID
- 9667
- 时间
- 6000ms
- 内存
- 2048MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者