线段树选做

1|0[NOIP2012]借教室


简单的区间加和区间查询

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using ldb = long double; //#define int i64 using vi = vector<int>; using pii = pair<int, int>; const int mod = 1e9 + 7; struct Node { int l, r, value, add; Node *left, *right; Node(int l, int r, int value, Node *left, Node *right) : l(l), r(r), value(value), left(left), right(right) { add = 0; } } *root; Node *build(int l, int r, const vector<int> &v) { if (l == r) { return new Node(l, r, v[l], nullptr, nullptr); } int mid = (l + r) / 2; Node *left = build(l, mid, v); Node *right = build(mid + 1, r, v); return new Node(l, r, min(left->value, right->value), left, right); } void mark(int v, Node *cur) { cur->add += v; cur->value += v; return; } void pushdown(Node *cur) { if (cur->add == 0) return; mark(cur->add, cur->left); mark(cur->add, cur->right); cur->add = 0; return; } void modify(int l, int r, int v, Node *cur) { if (l > cur->r or r < cur->l) return; if (l <= cur->l and cur->r <= r) { mark(v, cur); return; } pushdown(cur); int mid = (cur->l + cur->r) / 2; if (l <= mid) modify(l, r, v, cur->left); if (r > mid) modify(l, r, v, cur->right); cur->value = min(cur->left->value, cur->right->value); return; } int query(int l, int r, Node *cur) { if (l > cur->r or r < cur->l) return INT_MAX; if (l <= cur->l and cur->r <= r) return cur->value; pushdown(cur); int mid = (cur->l + cur->r) / 2, res = INT_MAX; if (l <= mid) res = min(res, query(l, r, cur->left)); if (r > mid) res = min(res, query(l, r, cur->right)); return res; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, m; cin >> n >> m; vi a(n + 1); for (int i = 1; i <= n; i++) cin >> a[i]; root = build(1, n, a); vi res; for (int i = 1, l, r, v; i <= m; i++) { cin >> v >> l >> r; if (query(l, r, root) < v) { cout << "-1\n" << i << "\n"; return 0; } modify(l, r, -v, root); } cout << "0\n"; return 0; }

2|0数据结构


https://ac.nowcoder.com/acm/problem/19246

维护复杂了一点

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using ldb = long double; #define int i64 using vi = vector<int>; struct Node { int l, r, value, square, add, mul; Node *left, *right; Node(int l, int r, int value, int square, Node *left, Node *right) : l(l), r(r), value(value), square(square), left(left), right(right) { add = 0, mul = 1; } } *root; Node *build(int l, int r, const vector<int> &v) { if (l == r) { return new Node(l, r, v[l], v[l] * v[l], nullptr, nullptr); } int mid = (l + r) / 2; Node *left = build(l, mid, v); Node *right = build(mid + 1, r, v); return new Node(l, r, left->value + right->value, left->square + right->square, left, right); } void markMul(int v, Node *cur) { cur->mul *= v; cur->add *= v; cur->value *= v; cur->square *= v * v; return; } void markAdd(int v, Node *cur) { cur->square += (cur->r - cur->l + 1) * v * v + 2 * v * cur->value; cur->value += v * (cur->r - cur->l + 1); cur->add += v; return; } void pushdown(Node *cur) { if (cur->mul != 1) { markMul(cur->mul, cur->left); markMul(cur->mul, cur->right); cur->mul = 1; } if (cur->add != 0) { markAdd(cur->add, cur->left); markAdd(cur->add, cur->right); cur->add = 0; } return; } int calcValue(int l, int r, Node *cur) { if (l > cur->r or r < cur->l) return 0; if (l <= cur->l and cur->r <= r) return cur->value; pushdown(cur); int mid = (cur->l + cur->r) / 2, sum = 0; if (l <= mid) sum += calcValue(l, r, cur->left); if (r > mid) sum += calcValue(l, r, cur->right); return sum; } int calcSquare(int l, int r, Node *cur) { if (l > cur->r or r < cur->l) return 0; if (l <= cur->l and cur->r <= r) return cur->square; pushdown(cur); int mid = (cur->l + cur->r) / 2, sum = 0; if (l <= mid) sum += calcSquare(l, r, cur->left); if (r > mid) sum += calcSquare(l, r, cur->right); return sum; } void modifyMul(int l, int r, int v, Node *cur) { if (l > cur->r or r < cur->l) return; if (l <= cur->l and cur->r <= r) { markMul(v, cur); return; } pushdown(cur); int mid = (cur->l + cur->r) / 2; if (l <= mid) modifyMul(l, r, v, cur->left); if (r > mid) modifyMul(l, r, v, cur->right); cur->value = cur->left->value + cur->right->value; cur->square = cur->left->square + cur->right->square; return; } void modifyAdd(int l, int r, int v, Node *cur) { if (l > cur->r or r < cur->l) return; if (l <= cur->l and cur->r <= r) { markAdd(v, cur); return; } pushdown(cur); int mid = (cur->l + cur->r) / 2; if (l <= mid) modifyAdd(l, r, v, cur->left); if (r > mid) modifyAdd(l, r, v, cur->right); cur->value = cur->left->value + cur->right->value; cur->square = cur->left->square + cur->right->square; return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, m; cin >> n >> m; vector<int> a(n + 1); for (int i = 1; i <= n; i++) cin >> a[i]; root = build(1, n, a); for (int opt, l, r, v; m; m--) { cin >> opt >> l >> r; if (opt == 1) { cout << calcValue(l, r, root) << "\n"; } else if (opt == 2) { cout << calcSquare(l, r, root) << "\n"; } else if (opt == 3) { cin >> v; modifyMul(l, r, v, root); } else { cin >> v; modifyAdd(l, r, v, root); } } return 0; }

3|0线段树


https://ac.nowcoder.com/acm/problem/212880

两两乘积和不好维护,可以用区间和、区间平方和导出。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using ldb = long double; #define int i64 int mod; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y /= 2; } return ans; } int inv(int x) { return power(x, mod - 2); } using vi = vector<int>; struct Node { int l, r, value, square, add, mul; Node *left, *right; Node(int l, int r, int value, int square, Node *left, Node *right) : l(l), r(r), value(value), square(square), left(left), right(right) { add = 0, mul = 1; } } *root; Node *build(int l, int r, const vector<int> &v) { if (l == r) { return new Node(l, r, v[l] % mod, v[l] * v[l] % mod, nullptr, nullptr); } int mid = (l + r) / 2; Node *left = build(l, mid, v); Node *right = build(mid + 1, r, v); return new Node(l, r, (left->value + right->value) % mod, (left->square + right->square) % mod, left, right); } void markMul(int v, Node *cur) { (cur->mul *= v) %= mod; (cur->add *= v) %= mod; (cur->value *= v) %= mod; (cur->square *= v * v % mod) %= mod; return; } void markAdd(int v, Node *cur) { (cur->square += (cur->r - cur->l + 1) * v % mod * v % mod + 2 * v % mod * cur->value % mod) %= mod; (cur->value += v * (cur->r - cur->l + 1) % mod) %= mod; (cur->add += v) %= mod; return; } void pushdown(Node *cur) { if (cur->mul != 1) { markMul(cur->mul, cur->left); markMul(cur->mul, cur->right); cur->mul = 1; } if (cur->add != 0) { markAdd(cur->add, cur->left); markAdd(cur->add, cur->right); cur->add = 0; } return; } int calcValue(int l, int r, Node *cur) { if (l > cur->r or r < cur->l) return 0; if (l <= cur->l and cur->r <= r) return cur->value; pushdown(cur); int mid = (cur->l + cur->r) / 2, sum = 0; if (l <= mid) (sum += calcValue(l, r, cur->left)) %= mod; if (r > mid) (sum += calcValue(l, r, cur->right)) %= mod; return sum; } int calcSquare(int l, int r, Node *cur) { if (l > cur->r or r < cur->l) return 0; if (l <= cur->l and cur->r <= r) return cur->square; pushdown(cur); int mid = (cur->l + cur->r) / 2, sum = 0; if (l <= mid) (sum += calcSquare(l, r, cur->left)) %= mod; if (r > mid) (sum += calcSquare(l, r, cur->right)) %= mod; return sum; } void modifyMul(int l, int r, int v, Node *cur) { if (l > cur->r or r < cur->l) return; if (l <= cur->l and cur->r <= r) { markMul(v, cur); return; } pushdown(cur); int mid = (cur->l + cur->r) / 2; if (l <= mid) modifyMul(l, r, v, cur->left); if (r > mid) modifyMul(l, r, v, cur->right); cur->value = (cur->left->value + cur->right->value) % mod; cur->square = (cur->left->square + cur->right->square) % mod; return; } void modifyAdd(int l, int r, int v, Node *cur) { if (l > cur->r or r < cur->l) return; if (l <= cur->l and cur->r <= r) { markAdd(v, cur); return; } pushdown(cur); int mid = (cur->l + cur->r) / 2; if (l <= mid) modifyAdd(l, r, v, cur->left); if (r > mid) modifyAdd(l, r, v, cur->right); cur->value = (cur->left->value + cur->right->value) % mod; cur->square = (cur->left->square + cur->right->square) % mod; return; } void solve(){ int n, m; cin >> n >> m >> mod; vector<int> a(n + 1); for (int i = 1; i <= n; i++) cin >> a[i]; root = build(1, n, a); for (int opt, l, r, v; m; m--) { cin >> opt >> l >> r; if (opt == 1) { cin >> v; modifyAdd(l, r, v, root); } else if (opt == 2) { cin >> v; modifyMul(l, r, v, root); } else { int x = calcValue(l, r, root), y = calcSquare(l, r, root); cout << (x * x % mod - y % mod + mod) % mod * inv(2) % mod << "\n"; } } } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; for( cin >> TC; TC; TC --) solve(); return 0; }

4|0仓鼠的鸡蛋


https://ac.nowcoder.com/acm/problem/226170

在线段树上二分查找,并返回坐标。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; const int inf = INT_MAX / 2; using vi = vector<int>; using pii = pair<int, int>; struct Node { int l, r, val, cnt; Node *left, *right; Node(int l, int r, int val, int cnt, Node *left = nullptr, Node *right = nullptr) : l(l), r(r), val(val), cnt(cnt), left(left), right(right) {}; } *root; Node *build(int l, int r, int m, int k) { if (l == r) return new Node(l, r, m, k); int mid = (l + r) / 2; Node *left = build(l, mid, m, k); Node *right = build(mid + 1, r, m, k); return new Node(l, r, m, 0, left, right); } void modify(int p, int delta, Node *cur) { if (p < cur->l or cur->r < p) return; if (cur->l == cur->r) { cur->val += delta; cur->cnt--; if (cur->cnt == 0) cur->val = -inf; return; } int mid = (cur->l + cur->r) / 2; if (p <= mid) modify(p, delta, cur->left); if (p > mid) modify(p, delta, cur->right); cur->val = max(cur->left->val, cur->right->val); return; } int query(int x, Node *cur) { if (cur->l == cur->r) return cur->l; if (cur->left->val >= x) return query(x, cur->left); if (cur->right->val >= x) return query(x, cur->right); return -1; } void solve() { int n, m, k; cin >> n >> m >> k; root = build(1, n, m, k); for (int x, l, r, ans, i = 1; i <= n; i++) { cin >> x; ans = query(x, root); cout << ans << "\n"; if (ans != -1) modify(ans, -x, root); } return; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; for (cin >> TC; TC; TC--) solve(); return 0; }

5|0P5490 【模板】扫描线


https://www.luogu.com.cn/problem/P5490

扫描线模板题

// luogu P5490 #include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; #define int i64 const int inf = INT_MAX / 2; using seg = array<int, 4>; // {x, y1, y2, v} using vi = vector<int>; struct Node { int l, r, value, cnt;// value 被覆盖子区间长度,cnt 当前区间被完整覆盖的次数。 Node *left, *right; Node(int l, int r, int value, int cnt, Node *left, Node *right) : l(l), r(r), value(value), cnt(cnt), left(left), right(right) {}; } *root; vi raw;// 原始坐标 int val(int x) { // // x 是原始值,返回哈希值 int i = lower_bound(raw.begin(), raw.end(), x) - raw.begin(); if (raw[i] != x) return -1; return i; } Node *build(int l, int r) { if (l == r) return new Node(l, r, 0, 0, nullptr, nullptr); int mid = (l + r) / 2; auto left = build(l, mid), right = build(mid + 1, r); return new Node(l, r, 0, 0, left, right); } void maintain(Node *cur) { if (cur->cnt > 0) cur->value = raw[cur->r + 1] - raw[cur->l]; else if (cur->left == nullptr) cur->value = 0; else cur->value = cur->left->value + cur->right->value; return; } void modify(int l, int r, int v, Node *cur) { if (l > cur->r or r < cur->l) return; if (l <= cur->l and cur->r <= r) { cur->cnt += v; maintain(cur); return; } int mid = (cur->l + cur->r) / 2; if (l <= mid) modify(l, r, v, cur->left); if (r > mid) modify(l, r, v, cur->right); maintain(cur); return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n; cin >> n; vector<seg> p; for (int i = 1, xa, xb, ya, yb; i <= n; i++) { cin >> xa >> ya >> xb >> yb; p.push_back(seg{xa, ya, yb, 1}); p.push_back(seg{xb, ya, yb, -1}); raw.push_back(ya), raw.push_back(yb); } sort(p.begin(), p.end()); sort(raw.begin(), raw.end()); raw.resize(unique(raw.begin(), raw.end()) - raw.begin()); int tot = raw.size() - 1; root = build(0, tot); modify(val(p[0][1]), val(p[0][2]) - 1, p[0][3], root); int res = 0; for (int i = 1; i < p.size(); i++) { res += (p[i][0] - p[i - 1][0]) * root->value; modify(val(p[i][1]), val(p[i][2]) - 1, p[i][3], root); } cout << res; return 0; }

6|0P4588 [TJOI2018] 数学计算


做法很多,这里提供一个用线段树解决的思路。用一个大小为Q的数组,初始全为1,操作 1 就是第i为修改为m,操作2就是第pos位修改为1,然后求一个区间乘积就好。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; #define int i64 const int inf = INT_MAX / 2; int mod; struct Node { int l, r, val; Node *left, *right; Node(int l, int r, int val, Node *left = nullptr, Node *right = nullptr) : l(l), r(r), val(val), left(left), right(right) {}; } *root; Node *build(int l, int r) { if (l == r) return new Node(l, r, 1); int mid = (l + r) / 2; auto left = build(l, mid), right = build(mid + 1, r); return new Node(l, r, 1, left, right); } void modify(int p, int val, Node *cur) { if (p < cur->l or p > cur->r) return; if (cur->l == cur->r) { cur->val = val % mod; return; } int mid = (cur->l + cur->r) / 2; if (p <= mid) modify(p, val, cur->left); if (p > mid) modify(p, val, cur->right); cur->val = (cur->left->val * cur->right->val) % mod; return; } using vi = vector<int>; void debug(Node *cur) { cerr << cur->l << " " << cur->r << " " << cur->val << "\n"; if (cur->left != nullptr)debug(cur->left), debug(cur->right); } void solve() { int n; cin >> n >> mod; root = build(1, n); for (int i = 1, opt, x; i <= n; i++) { cin >> opt >> x; if (opt == 1) modify(i, x, root); else modify(x, 1, root); cout << root->val << "\n"; } return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; for (cin >> TC; TC; TC--) solve(); return 0; }

7|0D. Traffic Jams in the Land


https://codeforces.com/problemset/problem/498/D

一个很有用的性质是lcm(2,3,4,5,6)=60,因此对于到达时间我们模60就好了。

然后对于线段树节点的信息{l,r,val[60]}就可以用val[i]表示i的时间到达l并走到r所需要的代价。这样线段是维护就变成了O(60logn)

#include <bits/stdc++.h> using namespace std; using vi = vector<int>; struct Node { int l, r; vector<int> val; Node *left, *right; Node(int l, int r, int x) : l(l), r(r), val(60) { left = right = nullptr; for (int i = 0; i < 60; i++) val[i] = 1 + (i % x == 0); } Node(int l, int r, Node *left, Node *right) : l(l), r(r), left(left), right(right), val(60) {} } *root; void maintain(Node *cur) { for (int i = 0, t; i < 60; i++) { t = cur->left->val[i]; cur->val[i] = t + cur->right->val[(i + t) % 60]; } return; } Node *build(int l, int r, const vi &v) { if (l == r) return new Node(l, r, v[l]); int mid = (l + r) / 2; Node *left = build(l, mid, v); Node *right = build(mid + 1, r, v); Node *cur = new Node(l, r, left, right); maintain(cur); return cur; } void modify(int p, int delta, Node *cur) { if (p < cur->l or cur->r < p) return; if (cur->l == cur->r) { for (int i = 0; i < 60; i++) cur->val[i] = 1 + (i % delta == 0); return; } int mid = (cur->l + cur->r) / 2; if (p <= mid) modify(p, delta, cur->left); if (p > mid) modify(p, delta, cur->right); maintain(cur); return; } int query(int l, int r, int start, Node *cur) { if (l > cur->r or r < cur->l) return 0; if (l <= cur->l and cur->r <= r) return cur->val[start]; int mid = (cur->l + cur->r) / 2, ans = 0; if (l <= mid) ans += query(l, r, (start + ans) % 60, cur->left); if (r > mid) ans += query(l, r, (start + ans) % 60, cur->right); return ans; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n; cin >> n; vi a(n + 1); for (int i = 1; i <= n; i++) cin >> a[i]; root = build(1, n, a); int m; cin >> m; for (char opt; m; m--) { cin >> opt; if (opt == 'C') { int x, d; cin >> x >> d; modify(x, d, root); } else { int x, y; cin >> x >> y, y--; cout << query(x, y, 0, root) << "\n"; } } return 0; }

8|0F - Vacation Query


要用线段树实现区间翻转和区间最长连续子段。

其实可以直接维护出最长的连续1的同时维护出最长连续0,当需要翻转的时候直接交换就好了。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; #define int i64 const int inf = INT_MAX / 2; using vi = vector<int>; struct Info { array<int, 2> pre, suf, val, len; Info() : pre{0, 0}, suf{0, 0}, val{0, 0}, len{0, 0} {} Info(int x) { pre[x] = suf[x] = val[x] = 1; pre[x ^ 1] = suf[x ^ 1] = val[x ^ 1] = 0; len[x] = 1, len[x ^ 1] = -inf; } void swap() { std::swap(pre[0], pre[1]); std::swap(suf[0], suf[1]); std::swap(val[0], val[1]); std::swap(len[0], len[1]); } friend Info operator+(Info x, Info y) { Info ans; for (int i = 0; i < 2; i++) { ans.pre[i] = std::max(x.pre[i], x.len[i] + y.pre[i]); ans.suf[i] = std::max(y.suf[i], x.suf[i] + y.len[i]); ans.val[i] = std::max({x.val[i], y.val[i], x.suf[i] + y.pre[i]}); ans.len[i] = x.len[i] + y.len[i]; } return ans; } }; struct Node { i32 l, r, tag; Info info; Node *left, *right; Node() {}; Node(int p, int v) : info(v) { l = r = p, tag = 0; left = right = nullptr; } Node(int l, int r, Node *left, Node *right) : l(l), r(r), left(left), right(right) { tag = 0; info = left->info + right->info; } }; void maintain(Node *cur) { if (cur->left == nullptr) return; cur->info = cur->left->info + cur->right->info; } void mark(Node *cur) { cur->tag ^= 1; cur->info.swap(); return; } void pushdown(Node *cur) { if (cur->tag == 0) return; if (cur->left != nullptr) { mark(cur->left); mark(cur->right); } cur->tag = 0; return; } Node *build(i32 l, i32 r, const string &s) { if (l == r) return new Node(l, s[l - 1] - '0'); i32 mid = (l + r) / 2; auto left = build(l, mid, s), right = build(mid + 1, r, s); return new Node(l, r, left, right); } Info query(i32 l, i32 r, Node *cur) { if (cur == nullptr) return Info(); if (l > cur->r or r < cur->l) return Info(); if (l <= cur->l and cur->r <= r) return cur->info; pushdown(cur); return query(l, r, cur->left) + query(l, r, cur->right); } void modify(i32 l, i32 r, Node *cur) { if (cur == nullptr) return; if (l > cur->r or r < cur->l) return; if (l <= cur->l and cur->r <= r) { mark(cur); return; } pushdown(cur); modify(l, r, cur->left); modify(l, r, cur->right); maintain(cur); } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); i32 n, q; string s; cin >> n >> q >> s; Node *root = build(1, n, s); for (i32 op, l, r; q; q--) { cin >> op >> l >> r; if (op == 1) modify(l, r, root); else cout << query(l, r, root).val[1] << "\n"; } return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/18422551.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示