1 并查集 (不封装,按秩合并)
int ancestor(int x) {return p[x] == x ? x : (p[x] = ancestor(p[x]));} bool test(int x, int y, bool un = false) { if ((x = ancestor(x)) == (y = ancestor(y))) return true; if (un) size[x] > size[y] ? std::swap(x, y) : (void)0, p[x] = y, size[y] += size[x]; return false; }
2 并查集 (封装)
struct UFind{ int sz, *p; UFind (): sz(0) {p = NULL;} ~UFind () {if(p) delete [] (p);} void resize(int size){ if(p) delete [] (p); p = new int[(sz = size) + 1]; for(int i = 0; i <= sz; i++) p[i] = i; } int ancestor(int x) {return x == p[x] ? x : p[x] = ancestor(p[x]);} bool test(int x, int y, bool un = false){ if((x = ancestor(x)) == (y = ancestor(y))) return true; if(un) p[x] = y; return false; } };
3 树状数组 (不封装)
#define lowbit(x) (x & -x) int sum(int h){ int s = 0; while(h){ s += a[h]; h -= lowbit(h); } return s; } int add(int h, int v){ while(h <= n){ a[h] += v; h += lowbit(h); } return v; }
4 树状数组 (封装,可清空)
struct BIT { #define lowbit(x) (x & -x) int n, ti, tag[N]; ll x[N]; BIT () : ti(0) {} inline void resize(int size) {n = size;} inline void clear() {++ti;} inline ll & recover(int id) {return tag[id] == ti ? x[id] : (tag[id] = ti, x[id] = 0);} ll sum(int h) {ll s = 0; for (; h > 0; h -= lowbit(h)) s += recover(h); return s;} void add(int h, ll v) {for (; h <= n; h += lowbit(h)) recover(h) += v;} };
5 线段树 (不封装)
#define segc int M = L + R - 1 >> 1, lc = id << 1, rc = lc | 1 void add(int id, int L, int R, int h, int v){ if(L == R) return void(st[id] += v); segc; h <= M ? add(lc, L, M, h, v) : add(rc, M + 1, R, h, v); x[id].v = x[lc].v + x[rc].v; } int range(int id, int L, int R, int ql, int qr){ if(ql <= L && qr >= R) return st[id]; segc, s = 0; if(ql <= M) s += range(lc, L, M, ql, min(qr, M)); if(qr > M) s += range(rc, M + 1, R, max(ql, M + 1), qr); return s; }
6 线段树 (封装)
struct ST{ #define segc int M = L + R - 1 >> 1, lc = id << 1, rc = lc | 1 int sz; struct node {int v, f; bool zero;} *x; ST (): sz(0) {x = NULL;} ~ST () {if(x) delete [] (x);} void resize(int size) {sz = size; int sz0 = sz << 3; if(x) delete [] (x); x = new node[sz0]; memset(x, 0, sz0 * sizeof(node));} void add(int h, int v) {add(1, 1, sz, h, v);} int range(int l, int r) {return query(1, 1, sz, l, r);} void add(int id, int L, int R, int h, int v){ if(L == R) return void(x[id].v += v); segc; h <= M ? add(lc, L, M, h, v) : add(rc, M + 1, R, h, v); x[id].v = x[lc].v + x[rc].v; } int query(int id, int L, int R, int ql, int qr){ if(ql <= L && R <= qr) return x[id].v; segc, s = 0; if(ql <= M) s += query(lc, L, M, ql, min(qr, M)); if(qr > M) s += query(rc, M + 1, R, max(ql, M + 1), qr); return s; } };
7 可持久化线段树 (add 操作)
int add(int _id, int L, int R, int h, int v){ int id = ++cnt; x[id] = x[_id]; x[id].v += v; if(L == R) return id; int M = L + R - 1 >> 1; if(h <= M) x[id].lc = add(x[id].lc, L, M, h, v); else x[id].rc = add(x[id].rc, M + 1, R, h, v); return id; }
8 伸展树 (Splay)
#define pa p[nd] #define root nd[0].c[0] struct node {int v, sz, p, c[2]; ll sum;} nd[N]; inline int dir(int x) {return x == x[nd].pa.c[1];} inline void update(int x){ x[nd].sz = x[nd].c[0][nd].sz + x[nd].c[1][nd].sz + 1; x[nd].sum = x[nd].c[0][nd].sum + x[nd].c[1][nd].sum + x[nd].v; } void rotate(int x){ int y = x[nd].p, d = !dir(x); nd[y[nd].c[!d] = x[nd].c[d]].p = y; x[nd].p = y[nd].p; y[nd].pa.c[dir(y)] = x; nd[x[nd].c[d] = y].p = x; update(y); } void splay(int x, int g = 0){ for(; x[nd].p != g; rotate(x)) if(x[nd].pa.p != g) rotate(dir(x) ^ dir(x[nd].p) ? x : x[nd].p); update(x); } void insert(int x){ int y = 0, d = 0; if(root) for(y = root; d = (val[x] < y[nd].v), y[nd].c[d]; y = y[nd].c[d]); y[nd].c[d] = x; nd[x].v = nd[x].sum = val[x]; nd[x].sz = 1; nd[x].p = y; nd[x].c[0] = nd[x].c[1] = 0; splay(x); } void erase(int x){ if(x[nd].p) splay(x); if(!(x[nd].c[0] && x[nd].c[1])){ int d = (x[nd].c[1] > 0); x[nd].c[d][nd].p = 0; root = x[nd].c[d]; }else{ int y; for(y = x[nd].c[1]; y[nd].c[0]; y = y[nd].c[0]); splay(y, x); nd[y[nd].c[0] = x[nd].c[0]].p = y; y[nd].p = 0; root = y; update(y); } } int kth(int x, int v){ if(x[nd].sz < v) return -1; for(int j; ; ){ j = x[nd].c[0][nd].sz; if(v == j + 1) return x; x = x[nd].c[v > j]; v > j ? (v -= j + 1) : v; } }
9 动态树 (Link-Cut Tree)
namespace LCT { #define pa p[nd] struct node {bool rev; int v, p, c[2];} nd[N]; inline int dir(int x) {return !nd[x].p ? -1 : x == nd[x].pa.c[0] ? 0 : x == nd[x].pa.c[1] ? 1 : -1;} inline void reverse(int x) {x && (std::swap(nd[x].c[0], nd[x].c[1]), nd[x].rev = !nd[x].rev);} void push_down(int x) {if (nd[x].rev) reverse(nd[x].c[0]), reverse(nd[x].c[1]), nd[x].rev = false;} void pull_down(int x) {if (~dir(x)) pull_down(nd[x].p); push_down(x);} inline void update(int x) {const int l = nd[x].c[0], r = nd[x].c[1]; nd[x].v = (l ? nd[l].v : 0) + (r ? nd[r].v : 0);} void rotate(int x) { int y = nd[x].p, d = !dir(x); nd[nd[y].c[!d] = nd[x].c[d]].p = y; nd[x].p = nd[y].p; if (~dir(y)) nd[y].pa.c[dir(y)] = x; nd[nd[x].c[d] = y].p = x; update(y); } void splay(int x) {for (pull_down(x); ~dir(x); rotate(x)) if (~dir(nd[x].p)) rotate(dir(x) ^ dir(nd[x].p) ? x : nd[x].p); update(x);} void access(int x) {for (int y = 0; x; y = x, x = nd[x].p) splay(x), nd[x].c[1] = y, update(x);} void make_root(int x) {access(x), splay(x), reverse(x);} int find_root(int x) {for (access(x), splay(x); push_down(x), nd[x].c[0]; x = nd[x].c[0]); return splay(x), x;} int split(int x, int y) {return make_root(x), access(y), splay(y), y;} void link(int x, int y) {make_root(x), nd[x].p = y;} void cut(int x, int y) {split(x, y), nd[x].p = nd[y].c[0] = 0, update(y);} void trylink(int x, int y) {x == y || (split(x, y), ~dir(x)) || (nd[x].p = y);} void trycut(int x, int y) {split(x, y), nd[y].c[0] == x && !nd[x].c[1] && (nd[x].p = nd[y].c[0] = 0, update(y), 0);} }
10 树堆 (Treap)
struct random_t{ ull seed; static const ull multiplier = 0x5deece66dll;; static const ull addend = 0xbll; static const ull mask = 0xffffffffffffll; random_t () {char *x = new char; seed = (ull)x; delete x;} unsigned int next(){ seed = (seed * multiplier + addend) & mask; return seed >> 16; } unsigned int next(unsigned int n){ return n * (ull)next() >> 32; } }rnd; #define pa p[nd] #define C(x) c[x][nd] #define root nd[0].c[0] struct node {int v, sz, pt; int c[2], p; unsigned priority;} nd[N]; int cnt = 0; inline int dir(int x) {return x == nd[x].pa.c[1];} inline void update(int x){ nd[x].sz = nd[x].C(0).sz + nd[x].C(1).sz + nd[x].pt; } void rotate(int x){ int y = nd[x].p, d = !dir(x); nd[nd[y].c[!d] = nd[x].c[d]].p = y; nd[x].p = nd[y].p; nd[y].pa.c[dir(y)] = x; nd[nd[x].c[d] = y].p = x; update(y); update(x); } void push_up(int x) {for(; x; x = nd[x].p) update(x);} void rotation(int x) {for(; nd[x].p && nd[x].priority < nd[x].pa.priority; ) rotate(x);} void insert(int v){ int x = 0, y = 0, d = 0; if(root) for(y = root; nd[y].v != v && nd[y].c[d = v > nd[y].v]; y = nd[y].c[d]); if(nd[y].v == v) {++nd[y].pt; push_up(y); return;} nd[y].c[d] = x = ++cnt; nd[x].v = v; nd[x].sz = nd[x].pt = 1; nd[x].p = y; nd[x].c[0] = nd[x].c[1] = 0; nd[x].priority = rnd.next(); push_up(y); rotation(x); } void erase(int v){ int x = 0, y = 0, d = 0; if(root) for(x = root; nd[x].v != v && nd[x].c[d = v > nd[x].v]; x = nd[x].c[d]); if(nd[x].v != v) return; if(nd[x].pt > 1) {--nd[x].pt; push_up(x); return;} for(; nd[x].c[0] && nd[x].c[1]; rotate(nd[x].c[d])) d = nd[x].C(0).priority > nd[x].C(1).priority; d = nd[x].c[1] > 0; y = nd[x].c[d]; nd[y].p = nd[x].p; nd[x].pa.c[dir(x)] = y; push_up(nd[y].p); } int rank(int v){ int x = 0, d = 0, k = 0; if(root) for(x = root; nd[x].v != v && nd[x].c[d = v > nd[x].v]; x = nd[x].c[d]) if(d) k += nd[x].C(0).sz + nd[x].pt; if(nd[x].v != v) return -1; return k + nd[x].C(0).sz; } int kth(int k){ int x = root; if(nd[x].sz < k) return -1; for(int j, z; ; ){ j = nd[x].C(0).sz; z = nd[x].pt; if(j <= k && k < j + z) return x; x = nd[x].c[k > j]; k > j ? (k -= j + z) : k; } } int prev(int v){ int x = 0, r = -1, d = 0; if(root) for(x = root; x; x = nd[x].c[d]) if(d = v > x[nd].v) up(r, nd[x].v); // too little return r; } int succ(int v){ int x = 0, r = INT_MAX, d = 0; if(root) for(x = root; x; x = nd[x].c[d]) if(!(d = v >= x[nd].v)) down(r, nd[x].v); // too large return r; }
11 析合树 (构造)
int n, p[N]; namespace DCTree { typedef std::pair <int, int> pr; const int N = ::N * 2; enum type {leaf, disjunct, conjunct} I[N]; pr st[20][N]; int stack1[N], stack2[N], stack[N]; int cnt, root, left[N], mid[N], right[N]; inline void up(pr &x, const pr &y) {x.first > y.first ? x.first = y.first : 0, x.second < y.second ? x.second = y.second : 0;} void build_sparse_table() { int i, j, k = n; pr *f, *g = *st; for (j = 0; 1 << (j + 1) <= n; ++j) { f = g, g = st[j + 1], k -= 1 << j; for (i = 1; i <= k; ++i) up(g[i] = f[i], f[i + (1 << j)]); } } inline bool is_consecutive(int L, int R) { int c = lg2(R - L); pr ans = st[c][L]; up(ans, st[c][R - (1 << c)]); return ans.second - ans.first == R - L - 1; } namespace ST { #define segc int M = (L + R - 1) >> 1, lc = id << 1, rc = lc | 1 struct node {int v, tag;} x[N * 4]; void build(int id, int L, int R) { x[id].v = L, x[id].tag = 0; if (L == R) return; segc; build(lc, L, M), build(rc, M + 1, R); } void add(int id, int L, int R, int ql, int qr, int v) { if (ql <= L && R <= qr) {x[id].v += v, x[id].tag += v; return;} segc; if (ql <= M) add(lc, L, M, ql, qr, v); if (qr > M) add(rc, M + 1, R, ql, qr, v); x[id].v = std::min(x[lc].v, x[rc].v) + x[id].tag; } int find_suf(int id, int L, int R, int v, int cv = 0) { if (cv + x[id].v > v) return -1; if (L == R) return L; segc, p = find_suf(lc, L, M, v, cv += x[id].tag); return ~p ? p : find_suf(rc, M + 1, R, v, cv); } } int pa[N], fc[N], nc[N], deg[N]; inline void link(int x, int px) {pa[x] = px, nc[x] = fc[px], fc[px] = x, ++deg[px];} void build() { int i, l, top1 = 0, top2 = 0, top = 0, &v = root, u; cnt = n; for (i = 1; i <= n; ++i) st[0][i] = pr(p[i], p[i]), left[i] = right[i] = i, I[i] = leaf; build_sparse_table(), ST::build(1, 1, n); for (i = 1; i <= n; ++i) { for (; top1 && p[i] > p[ stack1[top1] ]; --top1) ST::add(1, 1, n, stack1[top1 - 1] + 1, stack1[top1], p[i] - p[ stack1[top1] ]); for (; top2 && p[i] < p[ stack2[top2] ]; --top2) ST::add(1, 1, n, stack2[top2 - 1] + 1, stack2[top2], p[ stack2[top2] ] - p[i]); stack1[++top1] = stack2[++top2] = i; l = ST::find_suf(1, 1, n, i); for (v = i; top && left[ u = stack[top] ] >= l; --top) if (I[u] == conjunct && is_consecutive(mid[u], i + 1)) right[u] = i, link(v, u), v = u; else if (is_consecutive(left[u], i + 1)) { I[++cnt] = conjunct, link(u, cnt), link(v, cnt); left[cnt] = left[u], right[cnt] = i, mid[cnt] = left[v], v = cnt; } else { I[++cnt] = disjunct, link(v, cnt); for (; top && !is_consecutive(left[u], i + 1); --top) link(u, cnt); link(u, cnt); left[cnt] = left[u], right[cnt] = i, v = cnt; } stack[++top] = v; } } }
12 Chtholly 树 (ODT) / set 维护连续段
namespace CTree { map C; map::iterator split(int pos) { map::iterator it = C.lower_bound(pos), jt = it; return it->first == pos ? it : C.emplace_hint(it, pos, (--jt)->second); } void modify(int l, int r, int v) { map::iterator it = split(l), jt = split(r), i, j; for (j = it; (i = j++) != jt; ) // do something on [i, j] C.erase(it, jt), C.emplace(l, v); // do something } }