数据结构代码汇总
1|0前言
本文均为本人码风qwq
另外有一些奇奇怪怪的东西……不知道算不算数据结构,就都放上了。
2|0线段树
2|1线段树(区间加)(题目:洛谷P3372)


#include <bits/stdc++.h> using namespace std; #define MAXN 1000005 typedef long long ll; ll n, m, a[MAXN], ans[MAXN << 2], tag[MAXN << 2], x, y, k, oper; inline ll ls(ll p) { return p << 1; } inline ll rs(ll p) { return p << 1 | 1; } inline void push_up(ll p) { //do add ans[p] = ans[ls(p)] + ans[rs(p)]; } void build(ll p, ll l, ll r) { tag[p] = 0; if (l == r) { ans[p] = a[l]; return; } ll mid = l + r >> 1; build(ls(p), l, mid); build(rs(p), mid + 1, r); push_up(p); } inline void f(ll p, ll l, ll r, ll k) { //only modify ancestor tag[p] += k; ans[p] += k * (r - l + 1); } inline void push_down(ll p, ll l, ll r) { ll mid = (l + r) >> 1; f(ls(p), l, mid, tag[p]); f(rs(p), mid + 1, r, tag[p]); tag[p] = 0; } inline void update(ll dl, ll dr, ll l, ll r, ll p, ll k) { if (dl <= l && r <= dr) { ans[p] += k * (r - l + 1); tag[p] += k; return; } push_down(p, l, r); ll mid = l + r >> 1; if (dl <= mid)update(dl, dr, l, mid, ls(p), k); if (mid < dr)update(dl, dr, mid + 1, r, rs(p), k); push_up(p); } ll query(ll qx, ll qy, ll l, ll r, ll p) { ll res = 0; if (qx <= l && r <= qy)return ans[p]; ll mid = l + r >> 1; push_down(p, l, r); if (qx <= mid)res += query(qx, qy, l, mid, ls(p)); if (qy > mid)res += query(qx, qy, mid + 1, r, rs(p)); return res; } int main() { scanf("%lld%lld", &n, &m); for (int i = 1; i <= n; i++)scanf("%lld", &a[i]); build(1, 1, n); while (m--) { scanf("%lld", &oper); if (oper == 1) { scanf("%lld%lld%lld", &x, &y, &k); update(x, y, 1, n, 1, k); } else { scanf("%lld%lld", &x, &y); printf("%lld\n", query(x, y, 1, n, 1)); } } return 0; }
2|2线段树(区间加、区间乘)(洛谷P3373)


#include <bits/stdc++.h> using namespace std; #define MAXN 1000005 typedef long long ll; ll n, m, a[MAXN], ans[MAXN << 2], add[MAXN << 2], mul[MAXN << 2], x, y, k, oper, mod; inline ll ls(ll p) { return p << 1; } inline ll rs(ll p) { return p << 1 | 1; } inline void push_up(ll p) { ans[p] = (ans[ls(p)] + ans[rs(p)]) % mod; } void build(ll p, ll l, ll r) { add[p] = 0; mul[p] = 1; if (l == r) { ans[p] = a[l]; return; } ll mid = l + r >> 1; build(ls(p), l, mid); build(rs(p), mid + 1, r); push_up(p); } inline void f(ll p, ll l, ll r,ll fa) { mul[p] = (mul[p] * mul[fa]) % mod; add[p] = (add[p] * mul[fa] + add[fa]) % mod; ans[p] = (ans[p] * mul[fa] + add[fa] * (r - l + 1)) % mod; } inline void push_down(ll p, ll l, ll r) { ll mid = (l + r) >> 1; f(ls(p), l, mid, p); f(rs(p), mid + 1, r, p); mul[p] = 1; add[p] = 0; } inline void update(ll dl, ll dr, ll l, ll r, ll p, ll k, bool op) { if (dr < l || r < dl)return; if (dl <= l && r <= dr) { if (op == 1) { ans[p] = (ans[p] + k * (r - l + 1)) % mod; add[p] = (add[p] + k) % mod; } else { ans[p] = (ans[p] * k) % mod; mul[p] = (mul[p] * k) % mod; add[p] = (add[p] * k) % mod; } return; } push_down(p, l, r); ll mid = l + r >> 1; if (dl <= mid)update(dl, dr, l, mid, ls(p), k, op); if (mid < dr)update(dl, dr, mid + 1, r, rs(p), k, op); push_up(p); } ll query(ll qx, ll qy, ll l, ll r, ll p) { if (qy < l || r < qx)return 0; if (qx <= l && r <= qy)return ans[p]; ll res = 0; ll mid = l + r >> 1; push_down(p, l, r); if (qx <= mid)res += query(qx, qy, l, mid, ls(p)); if (qy > mid)res += query(qx, qy, mid + 1, r, rs(p)); return res % mod; } int main() { scanf("%lld%lld%lld", &n, &m, &mod); for (int i = 1; i <= n; i++)scanf("%lld", &a[i]); build(1, 1, n); while (m--) { scanf("%lld", &oper); switch (oper) { case 1: scanf("%lld%lld%lld", &x, &y, &k); update(x, y, 1, n, 1, k, 0); break; case 2: scanf("%lld%lld%lld", &x, &y, &k); update(x, y, 1, n, 1, k, 1); break; default: scanf("%lld%lld", &x, &y); printf("%lld\n", query(x, y, 1, n, 1)); } } return 0; }
2|3线段树(区间最大连续子序列)(洛谷P4513)


#include <bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 5; int n, m, t[MAXN << 2], sum[MAXN << 2], L[MAXN << 2], R[MAXN << 2]; struct node { int t, sum, L, R; }; inline int ls(int p) { return p << 1; } inline int rs(int p) { return p << 1 | 1; } inline void push_up(int p) { sum[p] = sum[ls(p)] + sum[rs(p)]; L[p] = max(L[ls(p)], sum[ls(p)] + L[rs(p)]); R[p] = max(R[rs(p)], sum[rs(p)] + R[ls(p)]); t[p] = max(max(t[ls(p)], t[rs(p)]), R[ls(p)] + L[rs(p)]); } void build(int p, int l, int r) { if (l == r) { cin >> t[p]; sum[p] = L[p] = R[p] = t[p]; return; } int mid = l + r >> 1; build(ls(p), l, mid); build(rs(p), mid + 1, r); push_up(p); } void update(int p, int l, int r, int x, int k) { if (l == r) { L[p] = R[p] = t[p] = sum[p] = k; return; } int mid = l + r >> 1; if (x <= mid) update(ls(p), l, mid, x, k); else update(rs(p), mid + 1, r, x, k); push_up(p); } node query(int p, int l, int r, int qx, int qy) { if (qx <= l && r <= qy) return (node){t[p], sum[p], L[p], R[p]}; int mid = l + r >> 1; if (qy <= mid) // all in left return query(ls(p), l, mid, qx, qy); else if (qx > mid) // all in right return query(rs(p), mid + 1, r, qx, qy); else { node ql = query(ls(p), l, mid, qx, qy), qr = query(rs(p), mid + 1, r, qx, qy); return (node){max(max(ql.t, qr.t), ql.R + qr.L), ql.sum + qr.sum, max(ql.L, ql.sum + qr.L), max(qr.R, qr.sum + ql.R)}; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; build(1, 1, n); int op, x, y; for (int i = 1; i <= m; i++) { cin >> op >> x >> y; if (op == 1) cout << query(1, 1, n, min(x, y), max(x, y)).t << '\n'; else update(1, 1, n, x, y); } return 0; }
2|4线段树合并(洛谷P4556)


#include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; int n, m, mx, head[MAXN], to[MAXN << 1], nxt[MAXN << 1], d[MAXN], g[MAXN][25], tot, cnt; int t[MAXN << 6], c[MAXN << 6], ch[MAXN << 6][2], root[MAXN], ans[MAXN]; struct node { int u, v, w; } q[MAXN]; inline void link(int u, int v) { to[tot] = v; nxt[tot] = head[u]; head[u] = tot++; } inline int ls(int p) { return p << 1; } inline int rs(int p) { return p << 1 | 1; } inline void init(int x, int fa) { g[x][0] = fa; d[x] = d[fa] + 1; for (int i = 1; 1 << i <= d[x]; i++) g[x][i] = g[g[x][i - 1]][i - 1]; for (int i = head[x]; ~i; i = nxt[i]) if (to[i] != fa) init(to[i], x); } inline int LCA(int u, int v) { if (d[u] < d[v]) swap(u, v); for (int i = 20; i >= 0; i--) if (d[g[u][i]] >= d[v]) u = g[u][i]; if (u == v) return u; for (int i = 20; i >= 0; i--) if (g[u][i] != g[v][i]) { u = g[u][i]; v = g[v][i]; } return g[u][0]; } inline void push_up(int p) { if (c[ch[p][0]] >= c[ch[p][1]]) { c[p] = c[ch[p][0]]; t[p] = t[ch[p][0]]; } else { c[p] = c[ch[p][1]]; t[p] = t[ch[p][1]]; } } inline void Insert(int &p, int l, int r, int x, int k) { if (!p) p = ++cnt; if (l == r) { c[p] += k; t[p] = l; return; } int mid = l + r >> 1; if (x <= mid) Insert(ch[p][0], l, mid, x, k); else Insert(ch[p][1], mid + 1, r, x, k); push_up(p); } inline int Merge(int l, int r, int x, int y) { if (!x || !y) return x + y; if (l == r) { c[x] += c[y]; t[x] = l; return x; } int mid = l + r >> 1; ch[x][0] = Merge(l, mid, ch[x][0], ch[y][0]); ch[x][1] = Merge(mid + 1, r, ch[x][1], ch[y][1]); push_up(x); return x; } inline void dfs(int x) { for (int i = head[x]; ~i; i = nxt[i]) if (d[to[i]] > d[x]) { dfs(to[i]); root[x] = Merge(1, mx, root[x], root[to[i]]); } if (c[root[x]]) ans[x] = t[root[x]]; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); memset(head, -1, sizeof(head)); cin >> n >> m; int u, v; for (int i = 1; i < n; i++) { cin >> u >> v; link(u, v); link(v, u); } init(1, 0); for (int i = 1; i <= m; i++) { cin >> q[i].u >> q[i].v >> q[i].w; mx = max(mx, q[i].w); } for (int i = 1; i <= m; i++) { int lca = LCA(q[i].u, q[i].v); Insert(root[q[i].u], 1, mx, q[i].w, 1); Insert(root[q[i].v], 1, mx, q[i].w, 1); Insert(root[lca], 1, mx, q[i].w, -1); if (g[lca][0]) Insert(root[g[lca][0]], 1, mx, q[i].w, -1); } dfs(1); for (int i = 1; i <= n; i++) cout << ans[i] << '\n'; return 0; }
2|5线段树维护单调栈(洛谷P4198)


#include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; int n, m, g[MAXN << 2]; double f[MAXN << 2], slp[MAXN]; inline int ls(int p) { return p << 1; } inline int rs(int p) { return p << 1 | 1; } inline void push_up(int p) { f[p] = max(f[ls(p)], f[rs(p)]); } inline int query(int p, int l, int r, double x) { if (f[p] <= x) return 0; if (x < slp[l]) return g[p]; if (l == r) return x < slp[l]; int mid = l + r >> 1; if (f[ls(p)] <= x) return query(rs(p), mid + 1, r, x); else return query(ls(p), l, mid, x) + g[p] - g[ls(p)]; } inline void update(int p, int l, int r, int x, int k) { if (l == x && r == x) { f[p] = 1.0 * k / x; g[p] = 1; return; } int mid = l + r >> 1; if (x <= mid) update(ls(p), l, mid, x, k); else update(rs(p), mid + 1, r, x, k); push_up(p); g[p] = g[ls(p)] + query(rs(p), mid + 1, r, f[ls(p)]); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; int x, y; for (int i = 1; i <= m; i++) { cin >> x >> y; slp[x] = 1.0 * y / x; update(1, 1, n, x, y); cout << g[1] << '\n'; } return 0; }
2|6李超线段树(P4097)


#include <bits/stdc++.h> using namespace std; const int mod1 = 39989; const int mod2 = 1e9; const int N = 1e5 + 5; const int M = 4e4 + 5; const double eps = 1e-9; int n, t[M << 3], tot; struct line { double k, b; } a[N]; inline int ls(int p) { return p << 1; } inline int rs(int p) { return p << 1 | 1; } inline int cmp(double x, double y) { if (x - y > eps) return 1; if (y - x > eps) return -1; return 0; } struct result { double x; int y; inline result() { } inline result(double _x, int _y) { x = _x, y = _y; } inline const bool operator<(const result &t) const { if (cmp(x, t.x) == -1) return true; if (cmp(x, t.x) == 1) return false; return y > t.y; } }; inline double calc(int x, int d) { return a[x].b + a[x].k * d; } inline void add(int x0, int y0, int x1, int y1) { if (x0 == x1) // slope = inf a[++tot] = (line){0, 1.0 * max(y0, y1)}; else { double slope = 1.0 * (y1 - y0) / (x1 - x0); a[++tot] = (line){slope, y0 - slope * x0}; } } inline void upd(int p, int l, int r, int k) { int &x = t[p], mid = l + r >> 1; if (cmp(calc(k, mid), calc(x, mid)) == 1) swap(k, x); int bl = cmp(calc(k, l), calc(x, l)), br = cmp(calc(k, r), calc(x, r)); if (bl == 1 || (!bl && k < x)) upd(ls(p), l, mid, k); if (br == 1 || (!br && k < x)) upd(rs(p), mid + 1, r, k); } inline void update(int p, int l, int r, int dl, int dr, int k) { if (dl <= l && r <= dr) { upd(p, l, r, k); return; } int mid = l + r >> 1; if (dl <= mid) update(ls(p), l, mid, dl, dr, k); if (mid < dr) update(rs(p), mid + 1, r, dl, dr, k); } result query(int p, int l, int r, int k) { // cout << p << ' ' << t[p] << ' ' << l << ' ' << r << ' ' << k << '\n'; if (r < k || k < l) return result(0, 0); int mid = l + r >> 1; double res = calc(t[p], k); if (l == r) return result(res, t[p]); return max({result(res, t[p]), query(ls(p), l, mid, k), query(rs(p), mid + 1, r, k)}); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int last = 0; cin >> n; while (n--) { int op; cin >> op; if (!op) { int x; cin >> x; x = (x + last - 1 + mod1) % mod1 + 1; last = query(1, 1, mod1, x).y; cout << last << '\n'; } else { int x0, y0, x1, y1; cin >> x0 >> y0 >> x1 >> y1; x0 = (x0 + last - 1 + mod1) % mod1 + 1; x1 = (x1 + last - 1 + mod1) % mod1 + 1; y0 = (y0 + last - 1 + mod2) % mod2 + 1; y1 = (y1 + last - 1 + mod2) % mod2 + 1; if (x0 > x1) swap(x0, x1), swap(y0, y1); add(x0, y0, x1, y1); update(1, 1, mod1, x0, x1, tot); } } return 0; }
3|0ST表
3|1ST表维护区间最大值(洛谷P3865)


#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n, m, st[N][25]; inline int query(int l, int r) { int k = log2(r - l + 1); return max(st[l][k], st[r - (1 << k) + 1][k]); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> st[i][0]; for (int i = 1; i <= 20; i++) for (int j = 1; j + (1 << i) - 1 <= n; j++) st[j][i] = max(st[j][i - 1], st[j + (1 << i - 1)][i - 1]); while (m--) { int l, r; cin >> l >> r; cout << query(l, r) << '\n'; } return 0; }
4|0树状数组
4|1树状数组(单点加,区间查询)(洛谷3374)


#include <bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 5; int n, m, t[MAXN << 2]; inline int lowbit(int x) { return x & -x; } void add(int x, int k) { while (x <= n) { t[x] += k; x += lowbit(x); } } int query(int x) { int res = 0; while (x) { res += t[x]; x -= lowbit(x); } return res; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; int tmp, op, x, y; for (int i = 1; i <= n; i++) { cin >> tmp; add(i, tmp); } while (m--) { cin >> op >> x >> y; if (op == 1) add(x, y); else cout << query(y) - query(x - 1) << '\n'; } return 0; }
4|2树状数组(区间加、单点查询)(洛谷P3368)


#include <bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 5; int n, m, t[MAXN << 2]; inline int lowbit(int x) { return x & -x; } void add(int x, int k) { while (x <= n) { t[x] += k; x += lowbit(x); } } int query(int x) { int res = 0; while (x) { res += t[x]; x -= lowbit(x); } return res; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; int tmp, op, x, y, k, last = 0; for (int i = 1; i <= n; i++) { cin >> tmp; add(i, tmp - last); last = tmp; } while (m--) { cin >> op; if (op == 1) { cin >> x >> y >> k; add(x, k); add(y + 1, -k); } else { cin >> x; cout << query(x) << '\n'; } } return 0; }
5|0平衡树
5|1平衡树(Treap)(洛谷P3369)


#include <bits/stdc++.h> using namespace std; const int MAXN = 3e6 + 5; const int INF = 0x3f3f3f3f; int n, oper, x; int ch[MAXN][2], val[MAXN], pri[MAXN], sz[MAXN], cnt[MAXN], sum, root; // ch[x][0]=left, ch[x][1]=right inline int add(int x) { sum++; // how many node val[sum] = x; // node value pri[sum] = rand(); // node priority sz[sum] = 1; // node size cnt[sum] = 1; // number of same value return sum; } inline void push_up(int x) { sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + cnt[x]; } void build() { root = add(-INF); ch[root][1] = add(INF); push_up(root); } void Rotate(int &x, int d) { int tmp = ch[x][d ^ 1]; ch[x][d ^ 1] = ch[tmp][d]; ch[tmp][d] = x; x = tmp; push_up(ch[x][d]); push_up(x); } void Insert(int &x, int v) { if (!x) { x = add(v); return; } if (v == val[x]) cnt[x]++; else { int b = v < val[x] ? 0 : 1; Insert(ch[x][b], v); if (pri[x] < pri[ch[x][b]]) Rotate(x, b ^ 1); } push_up(x); } void Remove(int &x, int v) { if (!x) // not find return; if (val[x] == v) // find { if (cnt[x] > 1) // more than 1 { cnt[x]--; push_up(x); } else if (ch[x][0] || ch[x][1]) // only 1, and has child { if (!ch[x][1] || pri[ch[x][0]] > pri[ch[x][1]]) { Rotate(x, 1); Remove(ch[x][1], v); } else { Rotate(x, 0); Remove(ch[x][0], v); } push_up(x); } else x = 0; return; } if (v < val[x]) // at left Remove(ch[x][0], v); else // at right Remove(ch[x][1], v); push_up(x); } int Rank(int x, int v) { if (!x) // not find return 0; if (v == val[x]) // find return sz[ch[x][0]] + 1; else if (v < val[x]) // at left return Rank(ch[x][0], v); else // at right return sz[ch[x][0]] + cnt[x] + Rank(ch[x][1], v); } int Value(int x, int v) { if (!x) // not find return INF; if (v <= sz[ch[x][0]]) // at left return Value(ch[x][0], v); else if (v <= sz[ch[x][0]] + cnt[x]) // find return val[x]; else // at right return Value(ch[x][1], v - (sz[ch[x][0]] + cnt[x])); } int Previous(int v) { int x = root, res; while (x) if (v > val[x]) { res = val[x]; x = ch[x][1]; // left } else x = ch[x][0]; // right return res; } int Next(int v) { int x = root, res; while (x) if (v < val[x]) { res = val[x]; x = ch[x][0]; // right } else x = ch[x][1]; // left return res; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; build(); while (n--) { cin >> oper >> x; switch (oper) { case 1: Insert(root, x); break; case 2: Remove(root, x); break; case 3: cout << Rank(root, x) - 1 << '\n'; break; case 4: cout << Value(root, x + 1) << '\n'; break; case 5: cout << Previous(x) << '\n'; break; default: cout << Next(x) << '\n'; } } return 0; }
5|2平衡树(FHQ-Treap)(推荐)(洛谷P3369)


#include <bits/stdc++.h> using namespace std; const int MAXN = 3e6 + 5; int root, val[MAXN], sz[MAXN], ch[MAXN][2], pri[MAXN], tot; int n, opt, x; inline int add(int x) { val[++tot] = x; sz[tot] = 1; pri[tot] = rand(); return tot; } inline void push_up(int x) { sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } int Merge(int x, int y) { if (!x || !y) return x + y; if (pri[x] < pri[y]) { ch[x][1] = Merge(ch[x][1], y); push_up(x); return x; } else { ch[y][0] = Merge(x, ch[y][0]); push_up(y); return y; } } void Split(int cur, int k, int &x, int &y) { if (!cur) { x = y = 0; return; } if (val[cur] <= k) // left { x = cur; Split(ch[cur][1], k, ch[cur][1], y); } else // right { y = cur; Split(ch[cur][0], k, x, ch[cur][0]); } push_up(cur); } int Find(int cur, int k) { while (true) if (sz[ch[cur][0]] >= k) cur = ch[cur][0]; else if (sz[ch[cur][0]] + 1 == k) return cur; else { k -= sz[ch[cur][0]] + 1; cur = ch[cur][1]; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n; int x, y, z, tmp; while (n--) { cin >> opt >> tmp; switch (opt) { case 1: // Add Split(root, tmp, x, y); root = Merge(Merge(x, add(tmp)), y); break; case 2: // Delete Split(root, tmp, x, z); Split(x, tmp - 1, x, y); y = Merge(ch[y][0], ch[y][1]); root = Merge(Merge(x, y), z); break; case 3: // Rank Split(root, tmp - 1, x, y); cout << sz[x] + 1 << '\n'; // left tree root = Merge(x, y); break; case 4: // Find Num cout << val[Find(root, tmp)] << '\n'; break; case 5: // Find Last Split(root, tmp - 1, x, y); cout << val[Find(x, sz[x])] << '\n'; root = Merge(x, y); break; default: // Find Next Split(root, tmp, x, y); cout << val[Find(y, 1)] << '\n'; root = Merge(x, y); } } return 0; }
5|3文艺平衡树(FHQ-Treap)(洛谷P3391)


#include <bits/stdc++.h> using namespace std; const int MAXN = 5e6; int root, val[MAXN], ch[MAXN][2], pri[MAXN], sz[MAXN], tot; bool f[MAXN]; inline int Add(int x) { val[++tot] = x; sz[tot] = 1; pri[tot] = rand(); return tot; } inline void push_up(int x) { sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } inline void push_down(int x) { swap(ch[x][0], ch[x][1]); if (ch[x][0]) f[ch[x][0]] ^= 1; if (ch[x][1]) f[ch[x][1]] ^= 1; f[x] = false; } int Merge(int x, int y) { if (!x || !y) return x + y; if (pri[x] < pri[y]) { if (f[x]) push_down(x); ch[x][1] = Merge(ch[x][1], y); push_up(x); return x; } else { if (f[y]) push_down(y); ch[y][0] = Merge(x, ch[y][0]); push_up(y); return y; } } void Split(int cur, int k, int &x, int &y) { if (!cur) { x = y = 0; return; } if (f[cur]) push_down(cur); if (sz[ch[cur][0]] < k) { x = cur; Split(ch[cur][1], k - sz[ch[cur][0]] - 1, ch[cur][1], y); } else { y = cur; Split(ch[cur][0], k, x, ch[cur][0]); } push_up(cur); } void print(int x) { if (!x) return; if (f[x]) push_down(x); print(ch[x][0]); cout << val[x] << ' '; print(ch[x][1]); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m, l, r, x, y, z; cin >> n >> m; for (int i = 1; i <= n; i++) root = Merge(root, Add(i)); while (m--) { cin >> l >> r; Split(root, l - 1, x, y); Split(y, r - l + 1, y, z); f[y] ^= 1; root = Merge(x, Merge(y, z)); } print(root); return 0; }
6|0可持久化
6|1主席树维护数组(洛谷P3919)


#include <bits/stdc++.h> using namespace std; const int MAXN = 1e6 + 5; int n, m, t[MAXN * 25], ch[MAXN * 25][2], tot, a[MAXN], root[MAXN]; void build(int l, int r, int &p) { p = ++tot; if (l == r) { t[p] = a[l]; return; } int mid = l + r >> 1; build(l, mid, ch[p][0]); build(mid + 1, r, ch[p][1]); } void update(int l, int r, int &p, int pre, int x, int k) { p = ++tot; ch[p][0] = ch[pre][0]; ch[p][1] = ch[pre][1]; if (l == r) { t[p] = k; return; } int mid = l + r >> 1; if (x <= mid) update(l, mid, ch[p][0], ch[pre][0], x, k); else update(mid + 1, r, ch[p][1], ch[pre][1], x, k); } int query(int l, int r, int p, int x) { if (l == r) return t[p]; int mid = l + r >> 1; return x <= mid ? query(l, mid, ch[p][0], x) : query(mid + 1, r, ch[p][1], x); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; build(1, n, root[0]); int x, y, z, v; for (int i = 1; i <= m; i++) { cin >> x >> y >> z; if (y == 1) { cin >> v; update(1, n, root[i], root[x], z, v); } else { cout << query(1, n, root[x], z) << '\n'; root[i] = root[x]; } } return 0; }
6|2主席树-权值线段树(洛谷P3834)


#include <bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; int n, m, cnt, root[MAXN]; struct node { int ls, rs, sz; } t[MAXN << 5]; inline int update(int pre, int l, int r, int k) { int root = ++cnt; t[root] = t[pre]; t[root].sz++; if (l == r) return root; int mid = l + r >> 1; if (k <= mid) t[root].ls = update(t[pre].ls, l, mid, k); else t[root].rs = update(t[pre].rs, mid + 1, r, k); return root; } inline int query(int p1, int p2, int l, int r, int k) { if (l == r) return l; int mid = l + r >> 1; if (k <= t[t[p2].ls].sz - t[t[p1].ls].sz) return query(t[p1].ls, t[p2].ls, l, mid, k); else return query(t[p1].rs, t[p2].rs, mid + 1, r, k + t[t[p1].ls].sz - t[t[p2].ls].sz); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; for (int i = 1, x; i <= n; i++) { cin >> x; root[i] = update(root[i - 1], -1e9, 1e9, x); } for (int i = 1, l, r, k; i <= m; i++) { cin >> l >> r >> k; cout << query(root[l - 1], root[r], -1e9, 1e9, k) << '\n'; } return 0; }
6|3可持久化平衡树(FHQ-Treap)(洛谷P3835)


#include <bits/stdc++.h> using namespace std; const int MAXN = 2.5e7 + 5; int ch[MAXN][2], val[MAXN], sz[MAXN], pri[MAXN], tot, root[MAXN], n; inline int add(int x) { val[++tot] = x; sz[tot] = 1; pri[tot] = rand(); return tot; } inline void push_up(int x) { sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } int Merge(int x, int y) { if (!x || !y) return x + y; if (pri[x] < pri[y]) { int tmp = add(0); val[tmp] = val[x]; pri[tmp] = pri[x]; sz[tmp] = sz[x]; ch[tmp][0] = ch[x][0]; ch[tmp][1] = ch[x][1]; ch[tmp][1] = Merge(ch[tmp][1], y); push_up(tmp); return tmp; } else { int tmp = add(0); val[tmp] = val[y]; pri[tmp] = pri[y]; sz[tmp] = sz[y]; ch[tmp][1] = ch[y][1]; ch[tmp][0] = ch[y][0]; ch[tmp][0] = Merge(x, ch[tmp][0]); push_up(tmp); return tmp; } } void Split(int cur, int k, int &x, int &y) { if (!cur) { x = y = 0; return; } if (val[cur] <= k) { x = add(0); val[x] = val[cur]; pri[x] = pri[cur]; sz[x] = sz[cur]; ch[x][0] = ch[cur][0]; ch[x][1] = ch[cur][1]; Split(ch[x][1], k, ch[x][1], y); push_up(x); } else { y = add(0); val[y] = val[cur]; pri[y] = pri[cur]; sz[y] = sz[cur]; ch[y][0] = ch[cur][0]; ch[y][1] = ch[cur][1]; Split(ch[y][0], k, x, ch[y][0]); push_up(y); } } int Find(int cur, int k) { while (true) if (sz[ch[cur][0]] >= k) cur = ch[cur][0]; else { k -= sz[ch[cur][0]]; if (!--k) return cur; cur = ch[cur][1]; } } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; int x, y, z, v, opt, a; for (int i = 1; i <= n; i++) { cin >> v >> opt >> a; root[i] = root[v]; switch (opt) { case 1: Split(root[i], a, x, y); root[i] = Merge(Merge(x, add(a)), y); break; case 2: Split(root[i], a, x, z); Split(x, a - 1, x, y); y = Merge(ch[y][0], ch[y][1]); root[i] = Merge(Merge(x, y), z); break; case 3: Split(root[i], a - 1, x, y); cout << sz[x] + 1 << '\n'; root[i] = Merge(x, y); break; case 4: cout << val[Find(root[i], a)] << '\n'; break; case 5: Split(root[i], a - 1, x, y); if (!x) printf("-2147483647\n"); else { cout << val[Find(x, sz[x])] << '\n'; root[i] = Merge(x, y); } break; default: Split(root[i], a, x, y); if (!y) { printf("2147483647\n"); continue; } cout << val[Find(y, 1)] << '\n'; root[i] = Merge(x, y); } } return 0; }
6|4可持久化Trie


int t[N * 30][2], val[N * 30], root[N], tot; inline void insert(int x, int last, int k) { for (int i = 27; i >= 0; i--) { val[x] = val[last] + 1; bool p = k >> i & 1; if (!t[x][p]) t[x][p] = ++tot; t[x][p ^ 1] = t[last][p ^ 1]; x = t[x][p]; last = t[last][p]; } val[x] = val[last] + 1; } inline int query(int x, int y, int k) { int res = 0; for (int i = 27; i >= 0; i--) { bool p = k >> i & 1; if (val[t[x][p ^ 1]] != val[t[y][p ^ 1]]) { res += 1 << i; x = t[x][p ^ 1], y = t[y][p ^ 1]; } else x = t[x][p], y = t[y][p]; } return res; }
7|0树套树
7|1线段树套FHQ-Treap(洛谷P3380)


#include <bits/stdc++.h> using namespace std; const int MAXN = 5e4 + 5; const int MAXM = 1e7 + 5; const int INF = 2147483647; int n, m, a[MAXN]; inline int read() { int s = 0, f = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') f = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * f; } namespace FHQ { int ch[MAXM][2], pri[MAXM], sz[MAXM], val[MAXM], tot = 0; // --- bottom --- inline int Add(int x) { val[++tot] = x; pri[tot] = rand(); sz[tot] = 1; return tot; } inline void push_up(int x) { sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } inline int Merge(int x, int y) { if (!x || !y) return x + y; if (pri[x] < pri[y]) { ch[x][1] = Merge(ch[x][1], y); push_up(x); return x; } else { ch[y][0] = Merge(x, ch[y][0]); push_up(y); return y; } } inline void Split(int cur, int k, int &x, int &y) { if (!cur) { x = y = 0; return; } if (val[cur] <= k) { x = cur; Split(ch[cur][1], k, ch[cur][1], y); } else { y = cur; Split(ch[cur][0], k, x, ch[cur][0]); } push_up(cur); } inline int Find(int cur, int k) { while (true) if (sz[ch[cur][0]] >= k) cur = ch[cur][0]; else if (sz[ch[cur][0]] + 1 == k) return cur; else { k -= sz[ch[cur][0]] + 1; cur = ch[cur][1]; } } // --- application --- inline void Insert(int &root, int k) { int x, y; Split(root, k, x, y); root = Merge(x, Merge(Add(k), y)); } inline void Delete(int &root, int k) { int x, y, z; Split(root, k, x, z); Split(x, k - 1, x, y); y = Merge(ch[y][0], ch[y][1]); root = Merge(x, Merge(y, z)); } inline int Rank(int root, int k) { int x, y; Split(root, k - 1, x, y); int ans = sz[x] + 1; root = Merge(x, y); return ans; } inline int Last(int root, int k) { int x, y; Split(root, k - 1, x, y); int ans = sz[x] ? val[Find(x, sz[x])] : -INF; root = Merge(x, y); return ans; } inline int Next(int root, int k) { int x, y; Split(root, k, x, y); int ans = sz[y] ? val[Find(y, 1)] : INF; root = Merge(x, y); return ans; } // --- level 2 application --- inline void build(int &root, int l, int r) { for (int i = l; i <= r; i++) Insert(root, a[i]); } } namespace SegTree { int t[MAXN << 2], root[MAXN << 2]; inline int ls(int p) { return p << 1; } inline int rs(int p) { return p << 1 | 1; } inline void build(int p, int l, int r) { FHQ::build(root[p], l, r); if (l == r) return; int mid = l + r >> 1; build(ls(p), l, mid); build(rs(p), mid + 1, r); } inline void update(int p, int l, int r, int pre, int k) { FHQ::Delete(root[p], a[pre]); FHQ::Insert(root[p], k); if (l == r) return; int mid = l + r >> 1; if (pre <= mid) update(ls(p), l, mid, pre, k); else update(rs(p), mid + 1, r, pre, k); } inline int Rank(int p, int qx, int qy, int l, int r, int k) { if (qx > r || qy < l) return 0; if (qx <= l && r <= qy) return FHQ::Rank(root[p], k) - 1; int mid = l + r >> 1; return Rank(ls(p), qx, qy, l, mid, k) + Rank(rs(p), qx, qy, mid + 1, r, k); } inline int Find(int l, int r, int k) { int x = 0, y = 1e8; while (x <= y) { int mid = x + y >> 1; if (Rank(1, l, r, 1, n, mid) + 1 <= k) x = mid + 1; else y = mid - 1; } return x - 1; } inline int Last(int p, int qx, int qy, int l, int r, int k) { if (qx > r || qy < l) return -INF; if (qx <= l && r <= qy) return FHQ::Last(root[p], k); int mid = l + r >> 1; return max(Last(ls(p), qx, qy, l, mid, k), Last(rs(p), qx, qy, mid + 1, r, k)); } inline int Next(int p, int qx, int qy, int l, int r, int k) { if (qx > r || qy < l) return INF; if (qx <= l && r <= qy) return FHQ::Next(root[p], k); int mid = l + r >> 1; return min(Next(ls(p), qx, qy, l, mid, k), Next(rs(p), qx, qy, mid + 1, r, k)); } } int main() { // ios::sync_with_stdio(false); // cin.tie(nullptr); // freopen("t.in", "r", stdin); n = read(); m = read(); for (int i = 1; i <= n; i++) a[i] = read(); SegTree::build(1, 1, n); int op, x, y, z; while (m--) { op = read(); x = read(); y = read(); if (op == 3) { SegTree::update(1, 1, n, x, y); a[x] = y; continue; } z = read(); switch (op) { case 1: printf("%d\n", SegTree::Rank(1, x, y, 1, n, z) + 1); break; case 2: printf("%d\n", SegTree::Find(x, y, z)); break; case 4: printf("%d\n", SegTree::Last(1, x, y, 1, n, z)); break; default: printf("%d\n", SegTree::Next(1, x, y, 1, n, z)); } } return 0; }
8|0LCT
8|1LCT(洛谷P3690)


#include <bits/stdc++.h> using namespace std; const int N = 3e5 + 5; int n, m, fa[N], ch[N][2], val[N], sum[N]; bool r[N]; inline bool isroot(int x) { return ch[fa[x]][0] == x || ch[fa[x]][1] == x; } inline void push_up(int x) { sum[x] = sum[ch[x][0]] ^ sum[ch[x][1]] ^ val[x]; } inline void f(int x) { swap(ch[x][0], ch[x][1]); r[x] ^= 1; } inline void push_down(int x) { if (!r[x]) return; if (ch[x][0]) f(ch[x][0]); if (ch[x][1]) f(ch[x][1]); r[x] = 0; } inline void Rotate(int x) { int y = fa[x], z = fa[y], k = ch[y][1] == x, w = ch[x][k ^ 1]; if (isroot(y)) ch[z][ch[z][1] == y] = x; ch[x][k ^ 1] = y; ch[y][k] = w; if (w) fa[w] = y; fa[y] = x; fa[x] = z; push_up(y); } stack<int> stk; inline void splay(int x) { int cur = x; stk.emplace(cur); while (isroot(cur)) stk.emplace(cur = fa[cur]); for (; !stk.empty(); stk.pop()) push_down(stk.top()); while (isroot(x)) { int fat = fa[x], fafa = fa[fat]; if (isroot(fat)) Rotate((ch[fat][0] == x) ^ (ch[fafa][0] == fat) ? x : fat); Rotate(x); } push_up(x); } inline void access(int x) { for (int y = 0; x; y = x, x = fa[x]) { splay(x); ch[x][1] = y; push_up(x); } } inline void makeRoot(int x) { access(x); splay(x); f(x); } inline int getRoot(int x) { access(x); splay(x); while (ch[x][0]) push_down(x), x = ch[x][0]; splay(x); return x; } inline void Split(int x, int y) { makeRoot(x); access(y); splay(y); } inline void link(int x, int y) { makeRoot(x); if (getRoot(y) != x) fa[x] = y; } inline void cut(int x, int y) { makeRoot(x); if (getRoot(y) == x && fa[y] == x && !ch[y][0]) { fa[y] = ch[x][1] = 0; push_up(x); } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> val[i]; while (m--) { int op, x, y; cin >> op >> x >> y; switch (op) { case 0: Split(x, y); cout << sum[y] << '\n'; break; case 1: link(x, y); break; case 2: cut(x, y); break; default: splay(x); val[x] = y; } } return 0; }
9|0K-D Tree
9|1K-D Tree(洛谷P4148/P4357)


typedef long long ll; const int N = 2e5 + 5; int n, m, tot, cnt; ll ls[N], rs[N], minx[N], maxx[N], miny[N], maxy[N], sum[N], sz[N], dim[N], id[N]; priority_queue<ll, vector<ll>, greater<ll>> q; struct node { ll x, y, val; } s[N]; inline bool cmpx(const int &x, const int &y) { return s[x].x < s[y].x; } inline bool cmpy(const int &x, const int &y) { return s[x].y < s[y].y; } inline ll sq(ll x) { return x * x; } inline ll dis(int x, int y) { return max(sq(s[x].x - minx[y]), sq(s[x].x - maxx[y])) + max(sq(s[x].y - miny[y]), sq(s[x].y - maxy[y])); } inline void upd(int x, int y) { minx[x] = min(minx[x], minx[y]), maxx[x] = max(maxx[x], maxx[y]); miny[x] = min(miny[x], miny[y]), maxy[x] = max(maxy[x], maxy[y]); } inline void push_up(int x) { minx[x] = maxx[x] = s[x].x, miny[x] = maxy[x] = s[x].y; if (ls[x]) upd(x, ls[x]); if (rs[x]) upd(x, rs[x]); sum[x] = sum[ls[x]] + sum[rs[x]] + s[x].val; sz[x] = sz[ls[x]] + sz[rs[x]] + 1; } inline int build(int l, int r) { if (l > r) return 0; int mid = l + r >> 1; double sdx = 0, sdy = 0, dx = 0, dy = 0; for (int i = l; i <= r; i++) sdx += s[id[i]].x, sdy += s[id[i]].y; sdx /= r - l + 1, sdy /= r - l + 1; for (int i = l; i <= r; i++) dx += sq(sdx - s[id[i]].x), dy += sq(sdy - s[id[i]].y); nth_element(id + l, id + mid, id + r + 1, dx > dy ? cmpx : cmpy); dim[id[mid]] = dx > dy; ls[id[mid]] = build(l, mid - 1); rs[id[mid]] = build(mid + 1, r); push_up(id[mid]); return id[mid]; } inline void query(int l, int r, int x) { if (l > r) return; int mid = l + r >> 1; ll tmp = sq(s[id[mid]].x - s[id[x]].x) + sq(s[id[mid]].y - s[id[x]].y); if (tmp > q.top()) q.pop(), q.emplace(tmp); ll dl = dis(id[x], ls[id[mid]]), dr = dis(id[x], rs[id[mid]]); if (dl > q.top() && dr > q.top()) { if (dl > dr) { query(l, mid - 1, x); if (dr > q.top()) query(mid + 1, r, x); } else { query(mid + 1, r, x); if (dl > q.top()) query(l, mid - 1, x); } } else { if (dl > q.top()) query(l, mid - 1, x); if (dr > q.top()) query(mid + 1, r, x); } }
10|0树链剖分
10|1树链剖分(洛谷P3384)


#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n, m, root, mod, a[N], head[N], to[N << 1], nxt[N << 1], tot; int dep[N], fa[N], sz[N], son[N], id[N], val[N], top[N], cnt; inline void link(int u, int v) { to[tot] = v; nxt[tot] = head[u]; head[u] = tot++; } namespace SegTree { int t[N << 2], tag[N << 2]; inline int ls(int p) { return p << 1; } inline int rs(int p) { return p << 1 | 1; } inline void push_up(int p) { t[p] = (t[ls(p)] + t[rs(p)]) % mod; } inline void f(int p, int l, int r, int k) { tag[p] += k; t[p] = (t[p] + k * (r - l + 1)) % mod; } inline void push_down(int p, int l, int r) { int mid = l + r >> 1; f(ls(p), l, mid, tag[p]); f(rs(p), mid + 1, r, tag[p]); tag[p] = 0; } inline void build(int p, int l, int r) { if (l == r) { t[p] = val[l] % mod; return; } int mid = l + r >> 1; build(ls(p), l, mid); build(rs(p), mid + 1, r); push_up(p); } inline void update(int p, int l, int r, int dl, int dr, int k) { if (dl <= l && r <= dr) { f(p, l, r, k); return; } push_down(p, l, r); int mid = l + r >> 1; if (dl <= mid) update(ls(p), l, mid, dl, dr, k); if (mid < dr) update(rs(p), mid + 1, r, dl, dr, k); push_up(p); } inline int query(int p, int l, int r, int qx, int qy) { if (qx <= l && r <= qy) return t[p]; push_down(p, l, r); int res = 0, mid = l + r >> 1; if (qx <= mid) res = (res + query(ls(p), l, mid, qx, qy)) % mod; if (mid < qy) res = (res + query(rs(p), mid + 1, r, qx, qy)) % mod; return res; } } namespace HLD { inline int rangeSum(int x, int y) { int res = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); res = (res + SegTree::query(1, 1, n, id[top[x]], id[x])) % mod; x = fa[top[x]]; } if (dep[x] > dep[y]) swap(x, y); return (res + SegTree::query(1, 1, n, id[x], id[y])) % mod; } inline int treeSum(int x) { return SegTree::query(1, 1, n, id[x], id[x] + sz[x] - 1); } inline void rangeUpd(int x, int y, int k) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); SegTree::update(1, 1, n, id[top[x]], id[x], k); x = fa[top[x]]; } if (dep[x] > dep[y]) swap(x, y); SegTree::update(1, 1, n, id[x], id[y], k); } inline void treeUpd(int x, int k) { SegTree::update(1, 1, n, id[x], id[x] + sz[x] - 1, k); } } inline void dfs1(int x, int f, int d) { fa[x] = f; dep[x] = d; sz[x] = 1; int mx = 0; for (int i = head[x]; ~i; i = nxt[i]) if (to[i] != f) { dfs1(to[i], x, d + 1); sz[x] += sz[to[i]]; if (sz[to[i]] > mx) { mx = sz[to[i]]; son[x] = to[i]; } } } inline void dfs2(int x, int tp) { id[x] = ++cnt; val[cnt] = a[x]; top[x] = tp; if (!son[x]) return; dfs2(son[x], tp); for (int i = head[x]; ~i; i = nxt[i]) if (to[i] != fa[x] && to[i] != son[x]) dfs2(to[i], to[i]); // new begin } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); memset(head, -1, sizeof(head)); cin >> n >> m >> root >> mod; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1, u, v; i < n; i++) { cin >> u >> v; link(u, v); link(v, u); } dfs1(root, 0, 1); dfs2(root, root); SegTree::build(1, 1, n); while (m--) { int op, x, y, k; cin >> op; switch (op) { case 1: cin >> x >> y >> k; HLD::rangeUpd(x, y, k % mod); break; case 2: cin >> x >> y; cout << HLD::rangeSum(x, y) << '\n'; break; case 3: cin >> x >> k; HLD::treeUpd(x, k % mod); break; default: cin >> x; cout << HLD::treeSum(x) << '\n'; } } return 0; }
11|0点分树
11|1点分树(洛谷P6329)


#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n, m, head[N], to[N << 1], nxt[N << 1], tot; int a[N], g[N << 1][20], pos[N], dep[N], sz[N], f[N], cnt, minn, root; bool vis[N]; vector<int> t[2][N]; inline void link(int u, int v) { to[tot] = v; nxt[tot] = head[u]; head[u] = tot++; } inline void dfs1(int x, int fa) { g[++cnt][0] = x; pos[x] = cnt; for (int i = head[x]; ~i; i = nxt[i]) if (to[i] != fa) { dep[to[i]] = dep[x] + 1; dfs1(to[i], x); g[++cnt][0] = x; } } inline void init() { for (int i = 1; 1 << i <= cnt; i++) for (int j = 1; j + (1 << i) <= cnt; j++) g[j][i] = min(g[j][i - 1], g[j + (1 << i - 1)][i - 1]); } inline int tmin(int x, int y) { return dep[x] < dep[y] ? x : y; } inline int dis(int x, int y) { if (pos[x] > pos[y]) swap(x, y); int l = pos[x], r = pos[y], k = log2(r - l + 1); int lca = tmin(g[l][k], g[r - (1 << k) + 1][k]); return dep[x] + dep[y] - (dep[lca] << 1); } inline int lowbit(int x) { return x & -x; } inline void add(int p, int op, int x, int k) { for (x++; x <= sz[p]; x += lowbit(x)) t[op][p][x] += k; } inline int query(int p, int op, int x) { int res = 0; for (x = min(x + 1, sz[p]); x; x -= lowbit(x)) res += t[op][p][x]; return res; } inline void getRoot(int x, int fa, int k) { sz[x] = 1; int res = 0; for (int i = head[x]; ~i; i = nxt[i]) if (to[i] != fa && !vis[to[i]]) { getRoot(to[i], x, k); sz[x] += sz[to[i]]; res = max(res, sz[to[i]]); } res = max(res, k - sz[x]); if (res < minn) { minn = res; root = x; } } inline void build(int x, int k) { vis[x] = true; sz[x] = k; t[0][x].resize(sz[x] + 1); t[1][x].resize(sz[x] + 1); for (int i = head[x]; ~i; i = nxt[i]) if (!vis[to[i]]) { root = 0, minn = 1e9; getRoot(to[i], 0, sz[to[i]]); f[root] = x; build(root, sz[to[i]] + 1); } } inline void update(int x, int k) { for (int i = x; i; i = f[i]) add(i, 0, dis(x, i), k); for (int i = x; f[i]; i = f[i]) add(i, 1, dis(x, f[i]), k); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); memset(head, -1, sizeof(head)); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1, u, v; i < n; i++) { cin >> u >> v; link(u, v); link(v, u); } dfs1(1, 0); init(); root = 0, minn = 1e9; getRoot(1, 0, n); build(root, n); for (int i = 1; i <= n; i++) update(i, a[i]); int last = 0; while (m--) { int op, x, y; cin >> op >> x >> y; x ^= last, y ^= last; if (op) update(x, y - a[x]), a[x] = y; else { last = query(x, 0, y); for (int i = x; f[i]; i = f[i]) { int tmp = dis(x, f[i]); if (y >= tmp) last += query(f[i], 0, y - tmp) - query(i, 1, y - tmp); } cout << last << '\n'; } } return 0; }
12|0分块
12|1区间众数(洛谷P4168)


#include <bits/stdc++.h> using namespace std; #define int long long const int N = 4e4 + 5; struct node { int val, id, x; } a[N]; struct Point { int num, cnt; inline Point(int _num = 0, int _cnt = 0) { num = _num, cnt = _cnt; } } f[205][205]; int n, m, sq, tot, sum[205][N], tmp[N], initnum[N]; int len, num[N], L[N], R[N]; inline bool cmp1(const node &x, const node &y) { return x.val < y.val; } inline bool cmp2(const node &x, const node &y) { return x.id < y.id; } inline int query(int l, int r) { Point res; if (num[r] - num[l] <= 2) { for (int i = l; i <= r; i++) tmp[a[i].x] = 0; for (int i = l; i <= r; i++) { tmp[a[i].x]++; if (tmp[a[i].x] > res.cnt || tmp[a[i].x] == res.cnt && a[i].x < res.num) res = (Point){a[i].x, tmp[a[i].x]}; } return initnum[res.num]; } res = f[num[l] + 1][num[r] - 1]; for (int i = l; i <= min(r, R[num[l]]); i++) tmp[a[i].x] = sum[num[r] - 1][a[i].x] - sum[num[l]][a[i].x]; for (int i = L[num[r]]; i <= r; i++) tmp[a[i].x] = sum[num[r] - 1][a[i].x] - sum[num[l]][a[i].x]; for (int i = l; i <= min(r, R[num[l]]); i++) { tmp[a[i].x]++; if (tmp[a[i].x] > res.cnt || tmp[a[i].x] == res.cnt && a[i].x < res.num) res = (Point){a[i].x, tmp[a[i].x]}; } for (int i = L[num[r]]; i <= r; i++) { tmp[a[i].x]++; if (tmp[a[i].x] > res.cnt || tmp[a[i].x] == res.cnt && a[i].x < res.num) res = (Point){a[i].x, tmp[a[i].x]}; } return initnum[res.num]; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i].val, a[i].id = i; sort(a + 1, a + 1 + n, cmp1); for (int i = 1; i <= n; i++) a[i].x = a[i].val == a[i - 1].val ? tot : ++tot, initnum[a[i].x] = a[i].val; sort(a + 1, a + 1 + n, cmp2); sq = sqrt(n); for (int i = 1; i <= n; i++) num[i] = (i - 1) / sq + 1; for (int i = 1; (i - 1) * sq <= n; i++) L[i] = (i - 1) * sq + 1, R[i] = min(i * sq, n), len = i; for (int i = 1; i <= len; i++) for (int j = 1; j <= R[i]; j++) sum[i][a[j].x]++; for (int i = 1; i <= len; i++) { memset(tmp, 0, sizeof(tmp)); Point res; for (int j = i; j <= len; j++) { for (int k = L[j]; k <= R[j]; k++) { tmp[a[k].x]++; if (tmp[a[k].x] > res.cnt || tmp[a[k].x] == res.cnt && a[k].x < res.num) res = (Point){a[k].x, tmp[a[k].x]}; } f[i][j] = res; } } int last = 0; while (m--) { int l, r; cin >> l >> r; l = (l + last - 1) % n + 1, r = (r + last - 1) % n + 1; if (l > r) swap(l, r); last = query(l, r); cout << last << '\n'; } return 0; }
13|0自动机
13|1AC自动机(ACAM)


queue<int> q; struct ACAM { int t[N][26], fail[N], tot, tag[N], stk[N], pos[N], tail; inline void insert(string s) { int cur = 0; for (char c : s) { c -= 'a'; if (!t[cur][c]) t[cur][c] = ++tot; cur = t[cur][c]; } tag[cur] += s.size(); } inline void build() { for (int i = 0; i < 26; i++) if (t[0][i]) { fail[t[0][i]] = 0; q.emplace(t[0][i]); } while (!q.empty()) { int x = q.front(); q.pop(); for (int i = 0; i < 26; i++) if (t[x][i]) { fail[t[x][i]] = t[fail[x]][i]; q.emplace(t[x][i]); } else t[x][i] = t[fail[x]][i]; } } };
13|2回文自动机(PAM)


struct PAM { int len[N], num[N], fail[N], t[N][26], tot = 1; string s; inline int getFail(int x, int i) { while (i - len[x] - 1 < 0 || s[i] != s[i - len[x] - 1]) x = fail[x]; return x; } inline void build() { int cur = 0; fail[0] = 1, len[1] = -1; for (int i = 0; i < s.size(); i++) { s[i] -= 'A'; int pos = getFail(cur, i); if (!t[pos][s[i]]) { fail[++tot] = t[getFail(fail[pos], i)][s[i]]; t[pos][s[i]] = tot; len[tot] = len[pos] + 2; } cur = t[pos][s[i]]; num[cur]++; } for (int i = tot; i >= 2; i--) num[fail[i]] += num[i]; } };
13|3后缀自动机(SAM)


struct SAM { int tot, last, len[N], fa[N], t[N][26]; inline SAM() { last = tot = 0; fa[0] = -1; } inline void insert(char c) { c -= 'a'; int cur = ++tot; len[cur] = len[last] + 1; int p = last; last = cur; while (~p && !t[p][c]) t[p][c] = cur, p = fa[p]; if (!~p) { fa[cur] = 0; return; } int x = t[p][c]; if (len[p] + 1 == len[x]) fa[cur] = x; else { len[++tot] = len[p] + 1; fa[tot] = fa[x]; memcpy(t[tot], t[x], sizeof(t[x])); while (~p && t[p][c] == x) t[p][c] = tot, p = fa[p]; fa[x] = fa[cur] = tot; } } }
13|4广义后缀自动机(广义SAM)


#include <bits/stdc++.h> using namespace std; const int N = 2e6 + 5; string s; long long ans; int n; struct SAM { int tot, last, fa[N], len[N], t[N][26]; inline SAM() { tot = last = 0; fa[0] = -1; } inline void insert(char c) { c -= 'a'; int cur = ++tot; len[cur] = len[last] + 1; int p = last; while (~p && !t[p][c]) t[p][c] = cur, p = fa[p]; last = cur; if (!~p) { fa[cur] = 0; ans += len[cur] - len[0]; return; } int x = t[p][c]; if (len[x] == len[p] + 1) fa[cur] = x; else { len[++tot] = len[p] + 1; fa[tot] = fa[x]; memcpy(t[tot], t[x], sizeof(t[x])); while (~p && t[p][c] == x) t[p][c] = tot, p = fa[p]; fa[x] = fa[cur] = tot; } ans += len[cur] - len[fa[cur]]; } } sam; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n; for (int i = 1; i <= n; i++) { string s; cin >> s; sam.last = 0; for (char c : s) sam.insert(c); } cout << ans; return 0; }
14|0线性基
14|1普通


ll p[70]; inline void build(ll x, ll k) { for (int i = 65; i >= 0; i--) if (x >> i & 1) { if (!p[i]) { p[i] = x; break; } x ^= p[i]; } }
14|2前缀版


struct Prefix_Hamel { ll p[65]; int pos[65]; inline void insert(ll x, int id) { for (int i = 60; i >= 0; i--) if (x >> i & 1) { if (!p[i]) { p[i] = x, pos[i] = id; break; } else if (pos[i] < id) swap(pos[i], id), swap(p[i], x); x ^= p[i]; } } inline ll query(int l) { ll res = 0; for (int i = 60; i >= 0; i--) if (pos[i] >= l) res = max(res, res ^ p[i]); return res; } }
14|3通用版(雾


struct Hamel { ll p[65]; int pos[65]; inline void insert(ll x, int id = 0) { for (int i = 60; i >= 0; i--) { if (x >> i & 1) { if (!p[i]) { p[i] = x, pos[i] = id; break; } else if (id > pos[i]) swap(pos[i], id), swap(p[i], x); x ^= p[i]; } } } inline ll query(int l = -1) { ll res = 0; for (int i = 60; i >= 0; i--) if (!~l || pos[i] >= l) res = max(res, res ^ p[i]); return res; } }
15|0后缀数据结构
15|1后缀数组(SA)


int n, m, c[N], sa[N], rk[N], id[N], prerk[N]; inline void build() { for (int i = 1; i <= n; i++) c[rk[i] = s[i]]++; for (int i = 1; i <= m; i++) c[i] += c[i - 1]; for (int i = n; i; i--) sa[c[rk[i]]--] = i; for (int i = 1, p; i <= n; i <<= 1) { p = 0; for (int j = n - i + 1; j <= n; j++) // second id[++p] = j; for (int j = 1; j <= n; j++) // first if (sa[j] > i) id[++p] = sa[j] - i; memset(c, 0, sizeof(c)); for (int j = 1; j <= n; j++) c[rk[j]]++; for (int j = 1; j <= m; j++) c[j] += c[j - 1]; for (int j = n; j; j--) sa[c[rk[id[j]]]--] = id[j]; memcpy(prerk, rk, sizeof(rk)); p = 0; for (int j = 1; j <= n; j++) rk[sa[j]] = prerk[sa[j]] == prerk[sa[j - 1]] && prerk[sa[j] + i] == prerk[sa[j - 1] + i] ? p : ++p; if (p == n) break; m = p; } }
15|2后缀自动机(SAM)


string s; struct SAM { int tot, last, len[N], fa[N], t[N][26]; inline SAM() { last = tot = 0; fa[0] = -1; } inline void insert(char c) { c -= 'a'; int cur = ++tot; len[cur] = len[last] + 1; int p = last; last = cur; while (~p && !t[p][c]) t[p][c] = cur, p = fa[p]; if (!~p) { fa[cur] = 0; return; } int x = t[p][c]; if (len[p] + 1 == len[x]) fa[cur] = x; else { len[++tot] = len[p] + 1; fa[tot] = fa[x]; memcpy(t[tot], t[x], sizeof(t[x])); while (~p && t[p][c] == x) t[p][c] = tot, p = fa[p]; fa[x] = fa[cur] = tot; } } }
15|3后缀数组扩展(求两串LCP)


struct Suffix_Array { string s; int n, m, sa[N], rk[N], height[N], prerk[N], c[N], id[N]; int st[N][25]; inline void build() { m = 'z'; memset(c, 0, sizeof(c)); memset(rk, 0, sizeof(rk)); for (int i = 1; i <= n; i++) c[rk[i] = s[i - 1]]++; for (int i = 1; i <= m; i++) c[i] += c[i - 1]; for (int i = n; i; i--) sa[c[rk[i]]--] = i; for (int i = 1, p; i < n; i <<= 1) { p = 0; for (int j = n - i + 1; j <= n; j++) id[++p] = j; for (int j = 1; j <= n; j++) if (sa[j] > i) id[++p] = sa[j] - i; memset(c, 0, sizeof(c)); for (int j = 1; j <= n; j++) c[rk[j]]++; for (int j = 1; j <= m; j++) c[j] += c[j - 1]; for (int j = n; j; j--) sa[c[rk[id[j]]]--] = id[j]; memcpy(prerk, rk, sizeof(rk)); p = 0; for (int j = 1; j <= n; j++) rk[sa[j]] = prerk[sa[j]] == prerk[sa[j - 1]] && prerk[sa[j] + i] == prerk[sa[j - 1] + i] ? p : ++p; if (p == n) break; m = p; } } inline void getHeight() { for (int i = 1, k = 0; i <= n; i++) { if (k) k--; while (s[i + k - 1] == s[sa[rk[i] - 1] + k - 1]) k++; height[rk[i]] = k; } } inline void initST() { for (int i = 1; i <= n; i++) st[i][0] = height[i]; for (int i = 1; i <= 22; i++) for (int j = 1; j + (1 << i) - 1 <= n; j++) st[j][i] = min(st[j][i - 1], st[j + (1 << i - 1)][i - 1]); } inline int query(int l, int r) { l = rk[l], r = rk[r]; if (l > r) swap(l, r); l++; int k = log2(r - l + 1); return min(st[l][k], st[r - (1 << k) + 1][k]); } }
16|0左偏树
16|1左偏树


int L[N], R[N], dep[N], val[N]; inline int Merge(int x, int y) { if (!x || !y) return x + y; if (val[x] > val[y]) swap(x, y); R[x] = Merge(R[x], y); if (dep[L[x]] < dep[R[x]]) swap(L[x], R[x]); dep[x] = dep[R[x]] + 1; return x; }
17|0并查集(打开有惊喜)
17|1并查集


struct DSU { private: int ch[N][2], fa[N]; bool rev[N]; inline bool isrt(int x) { return ch[fa[x]][0] == x || ch[fa[x]][1] == x; } inline void reverse(int x) { swap(ch[x][0], ch[x][1]); rev[x] ^= 1; } inline void push_down(int x) { if (rev[x]) { if (ch[x][0]) reverse(ch[x][0]); if (ch[x][1]) reverse(ch[x][1]); rev[x] = 0; } } inline void rotate(int x) { int y = fa[x], z = fa[y], k = ch[y][1] == x; if (isrt(y)) ch[z][ch[z][1] == y] = x; fa[x] = z; fa[ch[y][k] = ch[x][k ^ 1]] = y; fa[ch[x][k ^ 1] = y] = x; } int stk[N]; inline void splay(int x) { int top = 1, cur = x; stk[1] = cur; while (isrt(cur)) stk[++top] = (cur = fa[cur]); while (top) push_down(stk[top--]); while (isrt(x)) { int y = fa[x], z = fa[y]; if (isrt(y)) rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y); rotate(x); } } inline void access(int x) { for (int y = 0; x; y = x, x = fa[x]) splay(x), ch[x][1] = y; } inline void makert(int x) { access(x); splay(x); reverse(x); } inline void split(int x, int y) { makert(x); access(y); splay(y); } public: inline void link(int x, int y) { makert(x); fa[x] = y; } inline void cut(int x, int y) { split(x, y); fa[x] = ch[y][0] = 0; } inline int find(int x) { access(x); splay(x); push_down(x); while (ch[x][0]) x = ch[x][0], push_down(x); splay(x); return x; } };
__EOF__

本文作者:creation_hy
本文链接:https://www.cnblogs.com/creation-hy/p/structure.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/creation-hy/p/structure.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】