voidadd(int x, T v){ int id = x / len; for (int i = x; i < min((id + 1) * len, n); ++i) prea[i] += v; for (int i = id + 1; i < min(n / len + 1, n); ++i) preb[i] += v; }
vector pre(N, vector<int>(b.size() + 1)); for (int i = 1; i < N; i++) { pre[i] = pre[i - 1]; for (int j = bs[i]; j < be[i]; j++) pre[i][a[j]]++; } vector<int> cnt(b.size() + 1); vector ma(N, vector<int>(N)); for (int i = 1; i < N; i++) { cnt.assign(b.size() + 1, 0); int maxa = 0; for (int j = i; j < N; j++) { ma[i][j] = ma[i][j - 1]; for (int k = bs[j]; k < be[j]; k++) { cnt[a[k]]++; if (cnt[a[k]] == maxa) ma[i][j] = min(ma[i][j], a[k]); if (cnt[a[k]] > maxa) maxa = cnt[a[k]], ma[i][j] = a[k]; } } }
auto query = [&](int l, int r) { int res = 0; if (bk[l] == bk[r - 1]) { for (int i = l; i < r; i++) cnt[a[i]] = 0; int maxa = 0; for (int i = l; i < r; i++) { cnt[a[i]]++; if (maxa == cnt[a[i]]) res = min(res, a[i]); if (maxa < cnt[a[i]]) maxa = cnt[a[i]], res = a[i]; } } else { int L = bk[l], R = bk[r - 1]; res = ma[L + 1][R - 1]; for (int i = l; i < be[L]; i++) cnt[a[i]] = pre[R - 1][a[i]] - pre[L][a[i]]; for (int i = bs[R]; i < r; i++) cnt[a[i]] = pre[R - 1][a[i]] - pre[L][a[i]]; int maxa = pre[R - 1][res] - pre[L][res]; for (int i = l; i < be[L]; i++) { cnt[a[i]]++; if (maxa == cnt[a[i]]) res = min(res, a[i]); if (maxa < cnt[a[i]]) maxa = cnt[a[i]], res = a[i]; } for (int i = bs[R]; i < r; i++) { cnt[a[i]]++; if (maxa == cnt[a[i]]) res = min(res, a[i]); if (maxa < cnt[a[i]]) maxa = cnt[a[i]], res = a[i]; } } return res; };
voidadd(int x, T v){ for (int i = x; i < a.size(); i += i & -i) a[i] += v; }
T sum(int x){ auto ans = T(); for (int i = x; i; i -= i & -i) ans += a[i]; return ans; } };
树状数组上二分
返回最后一个使前缀和小于指定值 $k$ 的下标 $x$ 的下一位,即权值树状数组第 $k$ 小。
1 2 3 4 5 6 7 8 9 10
intkth(T k){ int x = 0; auto cur = T(); for (int i = bit_floor(a.size()); i; i >>= 1) { if (x + i >= a.size()) continue; if (cur + a[x + i] >= k) continue; x += i, cur += a[x]; } return x + 1; }
template<typename Info, typename Tag> structSegmentTree { vector<Info> seg; vector<Tag> tag; explicitSegmentTree(const vector<Info> &val) : seg(val.size() * 4), tag(val.size() * 4) { auto build = [&](auto &&self, int u, int l, int r) { if (r - l == 1) { seg[u] = val[l]; return; } int m = l + r >> 1; self(self, u << 1, l, m); self(self, u << 1 | 1, m, r); seg[u] = Info::merge(seg[u << 1], seg[u << 1 | 1]); }; build(build, 1, 0, val.size()); } voidpush(int u, int l, int r){ int m = l + r >> 1; seg[u << 1].apply(tag[u], l, m); tag[u << 1].apply(tag[u], l, m); seg[u << 1 | 1].apply(tag[u], m, r); tag[u << 1 | 1].apply(tag[u], m, r); tag[u] = Tag(); } voidapply(int u, int l, int r, int ql, int qr, const Tag &t){ if (l >= qr || r <= ql) return; if (l >= ql && r <= qr) { seg[u].apply(t, l, r); tag[u].apply(t, l, r); return; } push(u, l, r); int m = l + r >> 1; apply(u << 1, l, m, ql, qr, t); apply(u << 1 | 1, m, r, ql, qr, t); seg[u] = Info::merge(seg[u << 1], seg[u << 1 | 1]); } Info query(int u, int l, int r, int ql, int qr){ if (l >= qr || r <= ql) returnInfo(); if (l >= ql && r <= qr) return seg[u]; push(u, l, r); int m = l + r >> 1; return Info::merge(query(u << 1, l, m, ql, qr), query(u << 1 | 1, m, r, ql, qr)); } };
template<typename Info, typename Tag> structSegmentTree { vector<Info> seg; vector<Tag> tag; vector<int> lch, rch; explicitSegmentTree() : seg(1), tag(1), lch(1), rch(1) { } intcreate(){ int x = seg.size(); seg.emplace_back(); tag.emplace_back(); lch.push_back(0); rch.push_back(0); return x; } voidpush(int u, int l, int r){ int m = l + r >> 1; seg[lch[u]].apply(tag[u], l, m); tag[lch[u]].apply(tag[u], l, m); seg[rch[u]].apply(tag[u], m, r); tag[rch[u]].apply(tag[u], m, r); tag[u] = Tag(); } voidapply(int u, int l, int r, int ql, int qr, const Tag &t){ if (l >= qr || r <= ql) return; if (l >= ql && r <= qr) { seg[u].apply(t, l, r); tag[u].apply(t, l, r); return; } push(u, l, r); int m = l + r >> 1; if (!lch[u]) lch[u] = create(); if (!rch[u]) rch[u] = create(); apply(lch[u], l, m, ql, qr, t); apply(rch[u], m, r, ql, qr, t); seg[u] = Info::merge(seg[lch[u]], seg[rch[u]]); } Info query(int u, int l, int r, int ql, int qr){ if (!u || l >= qr || r <= ql) returnInfo(); if (l >= ql && r <= qr) return seg[u]; push(u, l, r); int m = l + r >> 1; return Info::merge(query(lch[u], l, m, ql, qr), query(rch[u], m, r, ql, qr)); } };
template<typename T> structSplay { int rt = 0; vector<T> val; vector<array<int, 2> > ch; vector<int> fa, sz, cnt; Splay() : val(1), ch(1), fa(1), sz(1), cnt(1) { rt = 0; } voidcreate(int f, T v){ val.push_back(v); ch.emplace_back(); fa.push_back(f); sz.push_back(1); cnt.push_back(1); } intget(int x)const{ return x == ch[fa[x]][1]; } voidpull(int x){ sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + cnt[x]; } voidrotate(int x){ int y = fa[x], z = fa[y], dir = get(x); if (z) ch[z][get(y)] = x; if (ch[x][dir ^ 1]) fa[ch[x][dir ^ 1]] = y; fa[y] = x, fa[x] = z; ch[y][dir] = ch[x][dir ^ 1], ch[x][dir ^ 1] = y; pull(y), pull(x); } voidsplay(int x){ for (int f; (f = fa[x]); rotate(x)) { if (fa[f]) rotate(get(x) == get(f) ? f : x); } rt = x; } voidinsert(T v){ int tot = val.size(); if (!rt) { create(rt, v), rt = tot; return; } int x = rt, f = 0; while (x) { f = x; if (val[x] == v) break; int dir = v > val[x]; x = ch[x][dir]; } if (!x && f) create(f, v), ch[f][val[f] < v] = tot, splay(tot); if (x) cnt[x]++, pull(x), splay(x); } intfind(T v){ int x = rt, f = 0; while (x) { f = x; if (val[x] == v) break; int dir = v > val[x]; x = ch[x][dir]; } if (!x && f) splay(f); if (x) splay(x); return x; } voidremove(T v){ int x = find(v); if (!x) return; if (cnt[x] > 1) { --cnt[x]; pull(x); return; } int l = ch[x][0], r = ch[x][1]; ch[x][0] = ch[x][1] = fa[x] = 0; if (!l && !r) { rt = 0; } elseif (!l) { rt = r, fa[r] = 0; } elseif (!r) { rt = l, fa[l] = 0; } else { int pre = l; while (ch[pre][1]) pre = ch[pre][1]; splay(pre); ch[pre][1] = r; fa[r] = pre; pull(pre); rt = pre; } } intrank(T v){ int x = rt, res = 0; while (x) { if (v < val[x]) { x = ch[x][0]; } else { res += sz[ch[x][0]]; if (v == val[x]) break; res += cnt[x]; x = ch[x][1]; } } if (x) splay(x); return res + 1; } T kth(int k){ int x = rt; while (x) { int lsz = sz[ch[x][0]]; if (k <= lsz) x = ch[x][0]; elseif (k <= lsz + cnt[x]) break; else k -= lsz + cnt[x], x = ch[x][1]; } if (x) splay(x); return val[x]; } T prev(T v){ int x = rt, res = 0; while (x) { if (val[x] < v) res = x, x = ch[x][1]; else x = ch[x][0]; } if (res) splay(res); return val[res]; } T next(T v){ int x = rt, res = 0; while (x) { if (val[x] > v) res = x, x = ch[x][0]; else x = ch[x][1]; } if (res) splay(res); return val[res]; } };
Link-Cut Tree
Link-Cut Tree 是一种用于高效维护动态森林(支持树的连接、分割)和路径查询的数据结构,其核心操作(连接、分割、路径查询等)的均摊时间复杂度为 $O(\log{n})$,广泛应用于动态图算法和网络流问题。
template<typename Info> structPersistentSegmentTree { vector<Info> seg; vector<int> lch, rch; explicitPersistentSegmentTree() : seg(1), lch(1), rch(1) { } intbuild(const vector<Info> &val){ auto build = [&](auto &&self, int u, int l, int r) { if (r - l == 1) { seg[u] = val[l]; return; } int m = l + r >> 1; self(self, lch[u] = create(), l, m); self(self, rch[u] = create(), m, r); seg[u] = Info::merge(seg[lch[u]], seg[rch[u]]); }; int rt = create(); build(build, rt, 1, val.size()); return rt; } intcreate(){ int x = seg.size(); seg.emplace_back(); lch.push_back(0); rch.push_back(0); return x; } intbranch(int u){ int v = create(); seg[v] = seg[u]; lch[v] = lch[u]; rch[v] = rch[u]; return v; } voidmodify(int u, int v, int l, int r, int x, Info k){ if (r - l == 1) { seg[v] = k; return; } int m = l + r >> 1; if (x < m) { int lu = lch[u]; rch[v] = rch[u]; modify(lu, lch[v] = create(), l, m, x, k); } else { int ru = rch[u]; lch[v] = lch[u]; modify(ru, rch[v] = create(), m, r, x, k); } seg[v] = Info::merge(seg[lch[v]], seg[rch[v]]); } Info query(int u, int l, int r, int ql, int qr){ if (!u || l >= qr || r <= ql) returnInfo(); if (l >= ql && r <= qr) return seg[u]; int m = l + r >> 1; return Info::merge(query(lch[u], l, m, ql, qr), query(rch[u], m, r, ql, qr)); } };
template<typename T> structPersistentSegmentTree { vector<T> seg; vector<int> lch, rch; explicitPersistentSegmentTree() : seg(1), lch(1), rch(1) { } intcreate(){ int x = seg.size(); seg.emplace_back(); lch.push_back(0); rch.push_back(0); return x; } intbranch(int u){ int v = create(); seg[v] = seg[u]; lch[v] = lch[u]; rch[v] = rch[u]; return v; } voidmodify(int u, int v, int l, int r, int x, T k){ if (r - l == 1) { seg[v] = seg[u] + k; return; } int m = l + r >> 1; if (x < m) { int lu = lch[u]; rch[v] = rch[u]; modify(lu, lch[v] = create(), l, m, x, k); } else { int ru = rch[u]; lch[v] = lch[u]; modify(ru, rch[v] = create(), m, r, x, k); } seg[v] = seg[lch[v]] + seg[rch[v]]; } intkth(int u, int v, int l, int r, int k){ int m = l + r >> 1; if (r - l == 1) return l; int x = seg[lch[v]] - seg[lch[u]]; if (k <= x) returnkth(lch[u], lch[v], l, m, k); returnkth(rch[u], rch[v], m, r, k - x); } };
template<typename T> structPersistentArray { vector<T> seg; vector<int> lch, rch; explicitPersistentArray() : seg(1), lch(1), rch(1) { } intcreate(){ int x = seg.size(); seg.emplace_back(); lch.push_back(0); rch.push_back(0); return x; } intbranch(int u){ int v = create(); seg[v] = seg[u]; lch[v] = lch[u]; rch[v] = rch[u]; return v; } voidmodify(int u, int v, int l, int r, int x, T k){ if (r - l == 1) { seg[v] = k; return; } int m = l + r >> 1; if (x < m) { int lu = lch[u]; rch[v] = rch[u]; modify(lu, lch[v] = create(), l, m, x, k); } else { int ru = rch[u]; lch[v] = lch[u]; modify(ru, rch[v] = create(), m, r, x, k); } } T query(int u, int l, int r, int x){ if (r - l == 1) return seg[u]; int m = l + r >> 1; return x < m ? query(lch[u], l, m, x) : query(rch[u], m, r, x); } };
structPDSU { int n; vector<int> rt; PersistentArray<int> p; explicitPDSU(int n): rt(1) { this->n = n; for (int i = 0; i < n; i++) { p.modify(0, 0, 0, n, i, -1); } } intbranch(int u){ int v = rt.size(); rt.push_back(p.branch(rt[u])); return v; } intfind(int u, int x){ int f = p.query(rt[u], 0, n, x); if (f < 0) return x; returnfind(u, f); } boolsame(int u, int x, int y){ returnfind(u, x) == find(u, y); } boolmerge(int u, int x, int y){ x = find(u, x), y = find(u, y); if (x == y) returnfalse; int sx = p.query(rt[u], 0, n, x); int sy = p.query(rt[u], 0, n, y); if (sx > sy) swap(x, y); p.modify(rt[u], rt[u], 0, n, x, sx + sy); p.modify(rt[u], rt[u], 0, n, y, x); returntrue; } };
structPersistent01Trie { staticconstexprint maxb = 24; vector<array<int, 2> > ch; vector<int> pre; Persistent01Trie() : ch(1), pre(1) { } intcreate(){ int x = ch.size(); ch.emplace_back(); pre.push_back(0); return x; } intbranch(int u){ int v = create(); ch[v] = ch[u]; pre[v] = pre[u]; return v; } voidinsert(int u, int v, int x){ pre[v] = pre[u] + 1; for (int i = maxb; i >= 0; i--) { int b = x >> i & 1; int cu = ch[u][b]; ch[v][b] = create(); ch[v][!b] = ch[u][!b]; pre[ch[v][b]] = pre[cu] + 1; u = cu, v = ch[v][b]; } } intquery(int u, int v, int x)const{ int res = 0; for (int i = maxb; i >= 0; i--) { int b = x >> i & 1; if (pre[ch[v][b ^ 1]] - pre[ch[u][b ^ 1]]) { u = ch[u][b ^ 1], v = ch[v][b ^ 1], res |= 1 << i; } else { u = ch[u][b], v = ch[v][b]; } } return res; } };
Fenwick<int> d(n + 1, m + 1), di(n + 1, m + 1), dj(n + 1, m + 1), dij(n + 1, m + 1);
auto apply = [&](int x1, int y1, int x2, int y2, int v) { auto set = [&](int x, int y, int v) { d.add(x, y, v); di.add(x, y, v * x); dj.add(x, y, v * y); dij.add(x, y, v * x * y); }; set(x1, y1, v); set(x1, y2 + 1, -v); set(x2 + 1, y1, -v); set(x2 + 1, y2 + 1, v); };
auto query = [&](int x1, int y1, int x2, int y2) { auto get = [&](int x, int y) { return d.sum(x, y) * (x + 1) * (y + 1) - di.sum(x, y) * (y + 1) - dj.sum(x, y) * (x + 1) + dij.sum(x, y); }; returnget(x2, y2) - get(x2, y1 - 1) - get(x1 - 1, y2) + get(x1 - 1, y1 - 1); };
structSegmentTree { vector<int> seg, lch, rch; explicitSegmentTree() : seg(1), lch(1), rch(1) { } intcreate(){ int y = seg.size(); seg.emplace_back(); lch.push_back(0); rch.push_back(0); return y; } voidmodify(int u, int l, int r, int x, int k){ if (r - l == 1) { seg[u] += k; return; } int m = l + r >> 1; if (x < m) { if (!lch[u]) lch[u] = create(); modify(lch[u], l, m, x, k); } else { if (!rch[u]) rch[u] = create(); modify(rch[u], m, r, x, k); } seg[u] = seg[lch[u]] + seg[rch[u]]; } intquery(int u, int l, int r, int ql, int qr){ if (!u || l >= qr || r <= ql) return0; if (l >= ql && r <= qr) return seg[u]; int m = l + r >> 1; returnquery(lch[u], l, m, ql, qr) + query(rch[u], m, r, ql, qr); } }; structNestedSegmentTree { vector<int> seg, lch, rch; SegmentTree segy; explicitNestedSegmentTree() : seg(1), lch(1), rch(1) { } intcreate(){ int y = segy.create(); int x = seg.size(); seg.push_back(y); lch.push_back(0); rch.push_back(0); return x; } voidmodify(int u, int lx, int rx, int ly, int ry, int x, int y, int k){ segy.modify(seg[u], ly, ry, y, k); if (rx - lx == 1) return; int mx = lx + rx >> 1; if (x < mx) { if (!lch[u]) lch[u] = create(); modify(lch[u], lx, mx, ly, ry, x, y, k); } else { if (!rch[u]) rch[u] = create(); modify(rch[u], mx, rx, ly, ry, x, y, k); } } intquery(int u, int lx, int rx, int ly, int ry, int qxl, int qxr, int qyl, int qyr){ if (!u || lx >= qxr || rx <= qxl) return0; if (lx >= qxl && rx <= qxr) return segy.query(seg[u], ly, ry, qyl, qyr); int mx = lx + rx >> 1; returnquery(lch[u], lx, mx, ly, ry, qxl, qxr, qyl, qyr) + query(rch[u], mx, rx, ly, ry, qxl, qxr, qyl, qyr); } };
structPersistentSegmentTree { vector<int> seg; vector<int> lch, rch; explicitPersistentSegmentTree() : seg(1), lch(1), rch(1) { } intcreate(){ int y = (int) seg.size(); seg.emplace_back(); lch.push_back(0); rch.push_back(0); return y; } voidmodify(int u, int l, int r, int y, int k){ if (r - l == 1) { seg[u] += k; return; } int m = l + r >> 1; if (y < m) { if (!lch[u]) lch[u] = create(); modify(lch[u], l, m, y, k); } else { if (!rch[u]) rch[u] = create(); modify(rch[u], m, r, y, k); } seg[u] = seg[lch[u]] + seg[rch[u]]; } intquery(vector<int> &u, vector<int> &v, int l, int r, int k){ if (r - l == 1) return l; int x = 0; for (auto i: u) x -= seg[lch[i]]; for (auto i: v) x += seg[lch[i]]; int m = l + r >> 1; if (k <= x) { for (auto &i: u) i = lch[i]; for (auto &i: v) i = lch[i]; returnquery(u, v, l, m, k); } else { for (auto &i: u) i = rch[i]; for (auto &i: v) i = rch[i]; returnquery(u, v, m, r, k - x); } } }; structFenwickNestedSegmentTree { vector<int> a; PersistentSegmentTree segy; explicitFenwickNestedSegmentTree(int n) : a(n) { for (int i = 1; i < n; i++) a[i] = segy.create(); } voidmodify(int x, int l, int r, int y, int k){ for (int i = x; i < a.size(); i += i & -i) { segy.modify(a[i], l, r, y, k); } } intkth(int l, int r, int lv, int rv, int v){ vector<int> rtu, rtv; for (int i = l; i; i -= i & -i) rtu.push_back(a[i]); for (int i = r; i; i -= i & -i) rtv.push_back(a[i]); return segy.query(rtu, rtv, lv, rv, v); } };