《算法竞赛进阶指南》0x40线段树
2022/1/28 1:04:39
本文主要是介绍《算法竞赛进阶指南》0x40线段树,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
来,骗(建树、查询)
#include <iostream> #include <cstdio> using namespace std; const int N = 1e6 + 10; int n, q, a[N]; struct SegmentTree { int l, r, val; }tr[4 * N]; //当前建立的是u号结点,范围是[l,r] void build(int u, int l, int r) { tr[u] = {l, r}; if (l == r) { //叶子结点的值,直接取a数组的值 tr[u].val = a[l]; return; } int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); //非叶子结点的值,由它的两个孩子决定 tr[u].val = tr[u << 1].val + tr[u << 1 | 1].val; } //当前查询的是u号结点,要查询的区间范围是[A,B] int query(int u, int A, int B) { if (A <= tr[u].l && tr[u].r <= B) { return tr[u].val; } int mid = tr[u].l + tr[u].r >> 1, ans = 0; if (A <= mid) { ans += query(u << 1, A, B); } if (mid < B) { ans += query(u << 1 | 1, A, B); } return ans; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); build(1, 1, n); //建立线段树 scanf("%d", &q); while (q --) { int A, B; scanf("%d%d", &A, &B); printf("%d\n", query(1, A, B)); //查询区间和 } return 0; }
数列区间最大值(建树、查询)
#include <iostream> #include <cstdio> using namespace std; const int N = 1e6 + 10; int n, q, a[N]; struct SegmentTree { int l, r, val; }tr[4 * N]; //当前建立的是u号结点,范围是[l,r] void build(int u, int l, int r) { tr[u] = {l, r}; if (l == r) { //叶子结点的值,直接取a数组的值 tr[u].val = a[l]; return; } int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); //非叶子结点的值,由它的两个孩子决定 tr[u].val = max(tr[u << 1].val, tr[u << 1 | 1].val); } //当前查询的是u号结点,要查询的区间范围是[A,B] int query(int u, int A, int B) { if (A <= tr[u].l && tr[u].r <= B) return tr[u].val; int mid = tr[u].l + tr[u].r >> 1, ans = -1e9; if (A <= mid) ans = max(ans, query(u << 1, A, B)); if (mid < B) ans = max(ans, query(u << 1 | 1, A, B)); return ans; } int main() { scanf("%d%d", &n, &q); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); build(1, 1, n); while (q --) { int A, B; scanf("%d%d", &A, &B); printf("%d\n", query(1, A, B)); } return 0; }
数列操作 (单点增加 、查询区间和)
#include <iostream> #include <cstdio> using namespace std; const int N = 1e5 + 10; int n, q, a[N]; struct SegmentTree { int l, r, val; }tr[4 * N]; //当前建立的是u号结点,范围是[l,r] void build(int u, int l, int r) { tr[u] = {l, r}; if (l == r) { //叶子结点的值,直接取a数组的值 tr[u].val = a[l]; return; } int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); //非叶子结点的值,由它的两个孩子决定 tr[u].val = tr[u << 1].val + tr[u << 1 | 1].val; } //当前查询的是u号结点; 将a[pos]改为x void modify(int u, int pos, int x) { if (tr[u].l == tr[u].r) { //查询到叶子结点,将其修改 tr[u].val += x; return; } int mid = tr[u].l + tr[u].r >> 1; if (pos <= mid) modify(u << 1, pos, x); else modify(u << 1 | 1, pos, x); //非叶子结点的值,由它的两个孩子决定 tr[u].val = tr[u << 1].val + tr[u << 1 | 1].val; } //当前查询的是u号结点; 要查询的区间范围是[A,B] int query(int u, int A, int B) { if (A <= tr[u].l && tr[u].r <= B) return tr[u].val; int mid = tr[u].l + tr[u].r >> 1, ans = 0; if (A <= mid) ans += query(u << 1, A, B); if (mid < B) ans += query(u << 1 | 1, A, B); return ans; } int main() { scanf("%d%d", &n, &q); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); build(1, 1, n); while (q --) { int k, s, t; scanf("%d%d%d", &k, &s, &t); if (k == 0) printf("%d\n", query(1, s, t)); else modify(1, s, t); } return 0; }
最大数(单点修改 、查询区间最大数)
#include <iostream> #include <cstdio> using namespace std; const int M = 2e5 + 10; int n, m, p; struct SegementTree { int l, r, val; }tr[4 * M]; void build(int u, int l, int r) { tr[u] = {l, r}; if (l == r) return; int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); } void modify(int u, int pos, int x) { if (tr[u].l == tr[u].r) { tr[u].val = x; return; } int mid = tr[u].l + tr[u].r >> 1; if (pos <= mid) modify(u << 1, pos, x); else modify(u << 1 | 1, pos, x); tr[u].val = max(tr[u << 1].val, tr[u << 1 | 1].val); } int query(int u, int A, int B) { if (A <= tr[u].l && tr[u].r <= B) return tr[u].val; int mid = tr[u].l + tr[u].r >> 1, ans = 0; if (A <= mid) ans = max(ans, query(u << 1, A, B)); if (mid < B) ans = max(ans, query(u << 1 | 1, A, B)); return ans; } int main() { scanf("%d%d", &m, &p); build(1, 1, m); char op[2]; int num, res = 0; while (m --) { scanf("%s%d", op, &num); if (op[0] == 'Q') res = query(1, n - num + 1, n), printf("%d\n", res); else modify(1, ++ n, ((long long)num + res) % p); } return 0; }
花神游历各国(特殊的单点修改 、查询区间和)
#include <iostream> #include <cstdio> #include <cmath> #define LL long long using namespace std; const int N = 1e5 + 10; int n, m, a[N]; struct SegmentTree { int l, r, maxx; LL val; }tr[4 * N]; void build(int u, int l, int r) { tr[u] = {l, r}; if (l == r) { tr[u].val = tr[u].maxx = a[l]; return; } int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); tr[u].val = tr[u << 1].val + tr[u << 1 | 1].val; tr[u].maxx = max(tr[u << 1].maxx, tr[u << 1 | 1].maxx); } void modify(int u, int A, int B) { if (tr[u].maxx <= 1) return; if (tr[u].l == tr[u].r) { tr[u].val = tr[u].maxx = sqrt(tr[u].val); return; } int mid = tr[u].l + tr[u].r >> 1; if (A <= mid) modify(u << 1, A, B); if (mid < B) modify(u << 1 | 1, A, B); tr[u].val = tr[u << 1].val + tr[u << 1 | 1].val; tr[u].maxx = max(tr[u << 1].maxx, tr[u << 1 | 1].maxx); } LL query(int u, int A, int B) { if (A <= tr[u].l && tr[u].r <= B) return tr[u].val; int mid = tr[u].l + tr[u].r >> 1; LL res = 0; if (A <= mid) res += query(u << 1, A, B); if (mid < B) res += query(u << 1 | 1, A, B); return res; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); build(1, 1, n); scanf("%d", &m); while (m --) { int x, A, B; LL res; scanf("%d%d%d", &x, &A, &B); if (x == 2) modify(1, A, B); else res = query(1, A, B), printf("%lld\n", res); } return 0; }
A Simple Problem with Integers (区间修改、区间查询)
#include <iostream> #include <cstdio> #define LL long long using namespace std; const int N = 1e6 + 10; int n, q, a[N], tag[N]; struct SegmentTree { int l, r; LL val, tag; }tr[4 * N]; void build(int u, int l, int r) { if (l == r) { tr[u] = {l, r, a[l], 0}; return; } int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); tr[u] = {l, r, tr[u << 1].val + tr[u << 1 | 1].val, 0}; } void update(int u, int x) { tr[u].tag += x; tr[u].val += (LL)(tr[u].r - tr[u].l + 1) * x; } void modify(int u, int A, int B, int x) { if (A <= tr[u].l && tr[u].r <= B) { update(u, x); return; } //在往下递归之前,检查一下是否需要下传懒标记 if (tr[u].tag) { update(u << 1, tr[u].tag); update(u << 1 | 1, tr[u].tag); tr[u].tag = 0; } int mid = tr[u].l + tr[u].r >> 1; if (A <= mid) modify(u << 1, A, B, x); if (mid < B) modify(u << 1 | 1, A, B, x); tr[u].val = tr[u << 1].val + tr[u << 1 | 1].val; } LL query(int u, int A, int B) { if (A <= tr[u].l && tr[u].r <= B) return tr[u].val; if (tr[u].tag) { update(u << 1, tr[u].tag); update(u << 1 | 1, tr[u].tag); tr[u].tag = 0; } int mid = tr[u].l + tr[u].r >> 1; LL res = 0; if (A <= mid) res += query(u << 1, A, B); if (mid < B) res += query(u << 1 | 1, A, B); return res; } int main() { scanf("%d%d", &n, &q); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); build(1, 1, n); while (q --) { int op, A, B, x; scanf("%d", &op); if (op == 1) { scanf("%d%d%d", &A, &B, &x); modify(1, A, B, x); } else { scanf("%d%d", &A, &B); LL res = query(1, A, B); printf("%lld\n", res); } } return 0; }
维护序列(区间修改、区间查询)
#include <iostream> #include <cstdio> #define LL long long using namespace std; const int N = 1e5 + 10; int n, m; LL P, a[N]; struct SegmentTree{ int l, r; LL val, t1, t2; //t1: 乘,t2:加 }tr[N * 4]; void build(int u, int l, int r) { if (l == r) { tr[u] = {l, r, a[l], 1, 0}; return; } int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); LL t = (tr[u << 1].val + tr[u << 1 | 1].val) % P; tr[u] = {l, r, t, 1, 0}; } //(data * t1 + t2) * x1 + x2 = data * (t1 * x1) + (t2 * x1 + x2) void update(int u, int x1, int x2) { tr[u].t1 = tr[u].t1 * x1 % P; tr[u].t2 = (tr[u].t2 * x1 + x2) % P; tr[u].val = (tr[u].val * x1 + (tr[u].r - tr[u].l + 1) * (LL)x2) % P; } void modify(int u, int A, int B, int x1, int x2) { if (A <= tr[u].l && tr[u].r <= B) { update(u, x1, x2); return; } //在往下递归之前,检查一下是否需要下传懒标记 //如果不判断,也不会影响结果 update(u << 1, tr[u].t1, tr[u].t2); update(u << 1 | 1, tr[u].t1, tr[u].t2); tr[u].t1 = 1; tr[u].t2 = 0; int mid = tr[u].l + tr[u].r >> 1; if (A <= mid) modify(u << 1, A, B, x1, x2); if (mid < B) modify(u << 1 | 1, A, B, x1, x2); tr[u].val = (tr[u << 1].val + tr[u << 1 | 1].val) % P; } LL query(int u, int A, int B) { if (A <= tr[u].l && tr[u].r <= B) return tr[u].val; update(u << 1, tr[u].t1, tr[u].t2); update(u << 1 | 1, tr[u].t1, tr[u].t2); tr[u].t1 = 1; tr[u].t2 = 0; int mid = tr[u].l + tr[u].r >> 1; LL res = 0; if (A <= mid) res += query(u << 1, A, B); if (mid < B) res += query(u << 1 | 1, A, B); return res % P; } int main() { scanf("%d%d", &n, &P); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); build(1, 1, n); scanf("%d", &m); while (m --) { int op, A, B, x; scanf("%d", &op); if (op == 1) scanf("%d%d%d", &A, &B, &x), modify(1, A, B, x, 0); else if (op == 2) scanf("%d%d%d", &A, &B, &x), modify(1, A, B, 1, x); else scanf("%d%d", &A, &B), printf("%lld\n", query(1, A, B)); } return 0; }
这篇关于《算法竞赛进阶指南》0x40线段树的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-28MQ底层原理资料详解:新手入门教程
- 2024-11-28MQ项目开发资料详解:新手入门教程
- 2024-11-28MQ项目开发资料详解:入门与初级用户指南
- 2024-11-28MQ消息队列资料入门教程
- 2024-11-28MQ消息队列资料:新手入门详解
- 2024-11-28MQ消息中间件资料详解与应用教程
- 2024-11-28MQ消息中间件资料入门教程
- 2024-11-28MQ源码资料详解与入门教程
- 2024-11-28MQ源码资料入门教程
- 2024-11-28RocketMQ底层原理资料详解