[关闭]
@oujunsong 2022-04-26T21:12:45.000000Z 字数 48386 阅读 100

各种代码模板

代码模板

卖价:


最大公约数 (gcd) [#nt01]:

  1. int gcd(int a, int b) {return b ? gcd(b, a % b) : a;}

快速幂 (递归版本) [#nt02]:

  1. ll PowerMod(ll a, ll n, ll m = mod) {
  2. if (!n || a == 1) return 1ll;
  3. ll s = PowerMod(a, n >> 1, m);
  4. s = s * s % m;
  5. return n & 1 ? s * a % m : s;
  6. }

快速幂 (非递归版本) [#nt03]:

  1. ll PowerMod(ll a, int n, ll c = 1) {for (; n; n >>= 1, a = a * a % mod) if (n & 1) c = c * a % mod; return c;}

扩展 Euclid 算法 (exgcd) [#nt04]:

  1. ll exgcd(ll a, ll b, ll &x, ll &y) {
  2. if (b) {ll d = exgcd(b, a % b, y, x); return y -= a / b * x, d;}
  3. else return x = 1, y = 0, a;
  4. }

基本预处理 [#nt05]:

  1. // 组合数
  2. // factorials, fact-inverses, unbounded
  3. void init() {
  4. int i;
  5. for (*fact = i = 1; i < N; ++i) fact[i] = (ll)fact[i - 1] * i % mod;
  6. --i, finv[i] = PowerMod(fact[i], mod - 2);
  7. for (; i; --i) finv[i - 1] = (ll)finv[i] * i % mod;
  8. }
  9. // factorials, fact-inverses, bounded
  10. void init(int n) {
  11. int i;
  12. for (*fact = i = 1; i <= n; ++i) fact[i] = (ll)fact[i - 1] * i % mod;
  13. finv[n] = PowerMod(fact[n], mod - 2);
  14. for (i = n; i; --i) finv[i - 1] = (ll)finv[i] * i % mod;
  15. }
  16. // inverses, factorials, fact-inverses, unbounded
  17. void init() {
  18. int i;
  19. for (inv[1] = 1, i = 2; i < N; ++i) inv[i] = ll(mod - mod / i) * inv[mod % i] % mod;
  20. for (*finv = *fact = i = 1; i < N; ++i) fact[i] = (ll)fact[i - 1] * i % mod, finv[i] = (ll)finv[i - 1] * inv[i] % mod;
  21. }
  22. // inverses, factorials, fact-inverses, bounded
  23. void init(int n) {
  24. int i;
  25. for (inv[1] = 1, i = 2; i <= n; ++i) inv[i] = ll(mod - mod / i) * inv[mod % i] % mod;
  26. for (*finv = *fact = i = 1; i <= n; ++i) fact[i] = (ll)fact[i - 1] * i % mod, finv[i] = (ll)finv[i - 1] * inv[i] % mod;
  27. }

线性筛素数 (筛最小素因子) [#nt06]:

  1. int pn = 0, c[N], p[78540];
  2. void sieve(int n) {
  3. int i, j, v;
  4. memset(c, -1, sizeof c);
  5. for (i = 2; i <= n; ++i) {
  6. if (!~c[i]) p[pn] = i, c[i] = pn++;
  7. for (j = 0; (v = i * p[j]) <= n && j <= c[i]; ++j) c[v] = j;
  8. }
  9. }

Miller-Rabin 素数测试 [#nt07]:

  1. // No pseudoprime below 2^64 to base 2, 3, 5, 7, 11, 13, 82, 373.
  2. const int test[8] = {2, 3, 5, 7, 11, 13, 82, 373};
  3. bool Miller_Rabin(ll n) {
  4. if (n < MAX) return !c[n] && n > 1;
  5. int c, i, j; ll s = n - 1, u, v;
  6. for (c = 0; !(s & 1); ++c, s >>= 1);
  7. for (i = 0; i < 8; ++i) {
  8. if (!(n % test[i])) return false;
  9. u = PowerMod(test[i], s, n);
  10. for (j = 0; j < c; ++j, u = v)
  11. if (v = MulMod(u, u, n), u != 1 && u != n - 1 && v == 1) return false;
  12. if (u != 1) return false;
  13. }
  14. return true;
  15. }

分解质因数 [#nt08]:

  1. // version 1
  2. inline void push(ll prime, int alpha) {pr[cnt] = prime, al[cnt++] = alpha;}
  3. // version 2
  4. inline void push(ll prime, int alpha) {
  5. map::iterator it = result.find(prime);
  6. it == result.end() ? (void)result.emplace(prime, alpha) : (void)(it->second += alpha);
  7. }
  8. void factor(ll n) {
  9. int i, j; cnt = 0; // result.clear();
  10. for (i = 0; n > 1; ) {
  11. if (n >= N) {
  12. for (; (ll)p[i] * p[i] <= n && n % p[i]; ++i);
  13. if (n % p[i]) return push(n, 1);
  14. } else i = c[n];
  15. for (j = 0; !(n % p[i]); n /= p[i], ++j); push(p[i], j);
  16. }
  17. }

线性筛 Euler φ 函数 [#nt09]:

  1. void sieve(int n) {
  2. int i, j, v; phi[1] = 1;
  3. memset(c, -1, sizeof c);
  4. for (i = 2; i <= n; ++i) {
  5. if (!~c[i]) p[pn] = i, c[i] = pn++, phi[i] = i - 1;
  6. for (j = 0; (v = i * p[j]) <= n && j < c[i]; ++j) c[v] = j, phi[v] = phi[i] * (p[j] - 1);
  7. if (v <= n) c[v] = j, phi[v] = phi[i] * p[j];
  8. }
  9. }

线性筛 Möbius μ 函数 [#nt10]:

  1. void sieve(int n) {
  2. int i, j, v; mu[1] = 1;
  3. memset(c, -1, sizeof c);
  4. for (i = 2; i <= n; ++i) {
  5. if (!~c[i]) p[pn] = i, c[i] = pn++, mu[i] = -1;
  6. for (j = 0; (v = i * p[j]) <= n && j < c[i]; ++j) c[v] = j, mu[v] = -mu[i];
  7. if (v <= n) c[v] = j;
  8. }
  9. }

遍历 ⌊n / i⌋ 的所有可能值 (旧版整除分块) [#nt11]:

  1. #define next(n, i) (n / (n / i + 1))
  2. for(i = n; i >= 1; i = j){
  3. j = next(n, i);
  4. // do something
  5. }
  6. #define _next(n, i) (n / (n / (i + 1)))
  7. for(i = 0; i < n; i = j){
  8. j = _next(n, i);
  9. // do something
  10. }
  11. // 0 1 100 1 2 50 2 3 33 3 4 25 4 5 20 5 6 16 16 6 7 14 7 8 12 8 9 11 9 10 10 10 11 9 11 12 8 12 13 7 14 15 6 16 17 5 20 21 4 25 26 3 33 34 2 50 51 1 100 101 0 ?

新版整除分块 [#nt12]:

  1. // int32 ver.
  2. int n, cnt, srn;
  3. int v[G];
  4. inline int ID(int x) {return x <= srn ? x : cnt + 1 - n / x;}
  5. {
  6. int i;
  7. srn = sqrt(n), cnt = srn * 2 - (srn * (srn + 1) > n);
  8. for (i = 1; i <= srn; ++i) v[i] = i, v[cnt - i + 1] = n / i;
  9. }
  10. // int64 ver.
  11. ll n, v[G];
  12. int cnt, srn;
  13. inline int ID(ll x) {return x <= srn ? x : cnt + 1 - n / x;}
  14. {
  15. int i;
  16. srn = sqrt(n), cnt = srn * 2 - (srn * (srn + 1ll) > n);
  17. for (i = 1; i <= srn; ++i) v[i] = i, v[cnt - i + 1] = n / i;
  18. }

杜氏求和法 / 杜教筛 [#nt13]:

  1. void Dsum() {
  2. int i, j, k, l, n, sq, _;
  3. for (i = 1; i <= cnt && v[i] < N; ++i) Mu[i] = smu[v[i]], Phi[i] = sphi[v[i]];
  4. for (; i <= cnt; ++i) {
  5. int &m = Mu[i]; ll &p = Phi[i];
  6. n = v[i], sq = sqrt(n), m = 1, p = n * (n + 1ll) / 2, l = n / (sq + 1);
  7. for (j = sq; j; --j) {
  8. _ = (k = n / j) - l, m -= _ * smu[j], p -= _ * sphi[j], l = k;
  9. if (j != 1 && k > sq) m -= Mu[_ = ID(k)], p -= Phi[_];
  10. }
  11. }
  12. }

大小步离散对数 [#nt14]:

  1. int Boy_Step_Girl_Step(){
  2. mii :: iterator it;
  3. ll boy = 1, girl = 1, i, t;
  4. for(i = 0; i < B; i++){
  5. m.insert(pr((int)boy, i)); // if there exists in map, then ignore it
  6. (boy *= a) %= p;
  7. }
  8. for(i = 0; i * B < p; i++){
  9. t = b * inv(girl) % p;
  10. it = m.find((int)t);
  11. if(it != m.end())
  12. return i * B + it->second;
  13. (girl *= boy) %= p;
  14. }
  15. return -1;
  16. }
  17. // input p and then B = (int)sqrt(p - 1);
  18. // inv(x) is the multiplicative inverse of x in Z[p].
  19. // mii: map <int, int> and m is a variable of which.

Pollard-Rho 素因数分解 [#nt15]:

  1. ll Pollard_Rho(ll n, int c) {
  2. ll i = 1, k = 2, x = rand() % (n - 1) + 1, y = x, p;
  3. for (; k <= 131072; ) {
  4. x = (MulMod(x, x, n) + c) % n;
  5. p = gcd<ll>((ull)(y - x + n) % n, n);
  6. if (p != 1 && p != n) return p;
  7. if (++i == k) y = x, k <<= 1;
  8. }
  9. return 0;
  10. }
  11. inline void push(ll prime, int alpha) {
  12. map::iterator it = result.find(prime);
  13. it == result.end() ? (void)result.insert(pr(prime, alpha)) : (void)(it->second += alpha);
  14. }
  15. void factor(ll n) {
  16. int i, j, k; ll p;
  17. for (i = 0; n != 1; )
  18. if (n >= MAX) {
  19. if (Miller_Rabin(n)) {push(n, 1); return;}
  20. for (k = 97; !(p = Pollard_Rho(n, k)); --k);
  21. factor(p); n /= p;
  22. } else {
  23. i = (c[n] ? c[n] : n);
  24. for (j = 0; !(n % i); n /= i, ++j);
  25. push(i, j);
  26. }
  27. }

字符串 Hash [#str01]:

  1. const ll mod[3] = {900000011, 998244353, 1000000007};
  2. const ll bas[3] = {4493, 8111, 8527};
  3. // you can choose your bases and modulos
  4. char s[S];
  5. ll pw[3][S], Hash[3][S];
  6. inline ll getHash(int id, int L, int R){ // str[L..R-1]
  7. ll J = (Hash[id][R] - Hash[id][L] * pw[id][R - L]) % mod[id];
  8. return J < 0 ? J + mod[id] : J;
  9. }
  10. // following is the pretreatment
  11. ll *f, *g;
  12. for(j = 0; j < 3; j++){
  13. f = Hash[j]; f[0] = 0;
  14. g = pw[j]; g[0] = 1;
  15. for(i = 0; i < n; i++){
  16. f[i + 1] = (f[i] * bas[j] + (s[i] - 'a')) % mod[j];
  17. g[i + 1] = g[i] * bas[j] % mod[j];
  18. }
  19. }

KMP 模式匹配 [#str02]:

  1. // pretreatment (border)
  2. for (j = *f = -1, i = 1; i < n; f[++i] = ++j)
  3. for (; ~j && s[j] != s[i]; j = f[j]);
  4. // KMP
  5. for (j = i = 0; i < _n; ++i) {
  6. for (; ~j && s[j] != m[i]; j = f[j]);
  7. if (++j == n) printf("%d ", i - s_n + 2);
  8. }

字典树 [#str03]:

  1. void append(char *s){
  2. char *p = s;
  3. int t = 1, id; // t = 0 is also OK
  4. for(; *p; ++p){
  5. id = *p - 97;
  6. t = d[t][id] ? d[t][id] : (d[t][id] = ++V);
  7. }
  8. ++val[t];
  9. }
  10. // the process of matching is just like going on a DFA, so omit it.

Aho-Corasick 自动机 [#str04]:

  1. void build(){
  2. int h, ta = 1, i, t, id;
  3. que[0] = 1;
  4. f[1] = 0;
  5. for(h = 0; h < ta; ++h)
  6. for(i = que[h], id = 0; id < 26; ++id){ // 26 is the size of char-set
  7. t = (f[i] ? d[f[i]][id] : 1); // 1 or 0 depend on the root of trie
  8. int &u = d[i][id];
  9. if(!u) {u = t; continue;}
  10. f[u] = t; val[u] |= val[t]; que[ta++] = u;
  11. la[u] = (v[t] ? t : la[t]);
  12. }
  13. }

后缀数组 (倍增构造) 与最长公共前缀 [#str05]:

  1. struct LCP {
  2. int n, *sa, *rnk, *st[LN];
  3. LCP () : n(0), sa(NULL), rnk(NULL) {memset(st, 0, sizeof st);}
  4. ~LCP () {
  5. if (sa) delete [] sa;
  6. if (rnk) delete [] rnk;
  7. for (int i = 0; i < LN; ++i) if (st[i]) delete [] st[i];
  8. }
  9. void construct(const char *s) {
  10. int i, j, k, m = 256, p, limit; n = strlen(s);
  11. int *x = new int[n + 1], *y = new int[n + 1], *buf = new int[max(n, m)], *f, *g = new int[n + 1];
  12. auto cmp = [this] (const int *a, const int u, const int v, const int l) {return a[u] == a[v] && (u + l >= n ? 0 : a[u + l]) == (v + l >= n ? 0 : a[v + l]);};
  13. if (sa) delete [] sa; sa = new int[n];
  14. if (rnk) delete [] rnk;
  15. for (i = 0; i < LN; ++i) if (st[i]) delete [] st[i], st[i] = 0;
  16. for (i = 0; i < n; ++i) sa[i] = i, x[i] = (unsigned char)s[i];
  17. std::sort(sa, sa + n, [s] (const int u, const int v) {return (unsigned char)s[u] < (unsigned char)s[v];});
  18. for (j = 1; j < n; j <<= 1, m = ++p) {
  19. std::iota(y, y + j, n - j), p = j;
  20. for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
  21. memset(buf, 0, m << 2);
  22. for (i = 0; i < n; ++i) ++buf[ x[y[i]] ];
  23. for (i = 1; i < m; ++i) buf[i] += buf[i - 1];
  24. for (i = n - 1; i >= 0; --i) sa[ --buf[ x[y[i]] ] ] = y[i];
  25. std::swap(x, y);
  26. x[*sa] = p = 1, x[n] = 0;
  27. for (i = 1; i < n; ++i) x[sa[i]] = (cmp(y, sa[i - 1], sa[i], j) ? p : ++p);
  28. if (p >= n) break;
  29. }
  30. if (rnk = x, n == 1) *x = 0;
  31. else for (i = 0; i < n; ++i) --x[i];
  32. delete [] buf, delete [] y;
  33. for (p = i = 0; i < n; ++i) {
  34. if (p && --p, !x[i]) continue;
  35. for (j = sa[x[i] - 1], limit = n - max(i, j); p < limit && s[i + p] == s[j + p]; ++p);
  36. g[ x[i] - 1 ] = p;
  37. }
  38. *st = g, k = n - 1;
  39. for (j = 0; 1 << (j + 1) < n; ++j) {
  40. k -= 1 << j, f = g, g = st[j + 1] = new int[k + 1];
  41. for (i = 0; i < k; ++i)
  42. g[i] = min(f[i], f[i + (1 << j)]);
  43. }
  44. }
  45. inline int operator () (const int u, const int v) {
  46. assert((unsigned)u < (unsigned)n && (unsigned)v < (unsigned)n);
  47. if (u == v) return n - u;
  48. int L, R, c; std::tie(L, R) = std::minmax(rnk[u], rnk[v]), c = lg2(R - L);
  49. return min(st[c][L], st[c][R - (1 << c)]);
  50. }
  51. };

后缀自动机 [#str06]:

  1. #define q d[p][x]
  2. int extend(int x) {
  3. for (p = np, val[np = ++cnt] = val[p] + 1; p && !q; q = np, p = pa[p]);
  4. if (!p) pa[np] = 1;
  5. else if (val[p] + 1 == val[q]) pa[np] = q;
  6. else {
  7. int nq = ++cnt;
  8. val[nq] = val[p] + 1, memcpy(d[nq], d[q], 104);
  9. pa[nq] = pa[q], pa[np] = pa[q] = nq;
  10. for (int Q = q; p && q == Q; q = nq, p = pa[p]);
  11. }
  12. return f[np] = 1, np;
  13. }
  14. #undef q

根据后缀自动机构造后缀树 [#str07]:

  1. void build() {
  2. int i, j, c; used[1] = true;
  3. for (i = cnt; i; --i) if (~pos[i])
  4. for (j = i; !used[j]; j = pa[j])
  5. c = pos[j] - val[pa[j]], pos[pa[j]] = pos[j],
  6. child[pa[j]][int(s[c])] = j, used[j] = true;
  7. // dfs(1);
  8. }

Z 算法 [#str08]:

  1. void Z() {
  2. int i, Max = 0, M = 0;
  3. for (i = 1; i < n; ++i) {
  4. z[i] = (i < Max ? std::min(z[i - M], Max - i) : 0);
  5. for (; s[z[i]] == s[i + z[i]]; ++z[i]);
  6. if (i + z[i] > Max) Max = i + z[i], M = i;
  7. }
  8. }

Manacher 回文串 [#str09]:

  1. void Manacher() {
  2. int n = 2, i, Max = 0, M = 0;
  3. t[0] = 2, t[1] = 1;
  4. for (i = 0; i < S; ++i) t[n++] = s[i], t[n++] = 1; t[n++] = 3;
  5. for (i = 0; i < n; ++i){
  6. f[i] = (i < Max ? std::min(f[M * 2 - i], Max - i) : 1);
  7. for(; t[i + f[i]] == t[i - f[i]]; ++f[i]);
  8. if (i + f[i] > Max) Max = i + f[i], M = i;
  9. }
  10. }

回文自动机 [#str10]:

  1. int get_fail(int x) {for (; ptr[~val[x]] != *ptr; x = fail[x]); return x;}
  2. int extend(int x) {
  3. int &q = d[p = get_fail(p)][x];
  4. if (!q) fail[++cnt] = d[get_fail(fail[p])][x], val[q = cnt] = val[p] + 2;
  5. return p = q;
  6. }
  7. val[1] = -1, p = 0, *fail = cnt = 1;

多串后缀自动机 / 广义后缀自动机 [#str11]:

  1. #define q d[p][x]
  2. #define try_split(v) { \
  3. if (val[p] + 1 == val[q]) v = q; \
  4. else { \
  5. int nq = ++cnt; \
  6. val[nq] = val[p] + 1, memcpy(d[nq], d[q], 104); \
  7. pa[nq] = pa[q], v = pa[q] = nq; \
  8. for (int Q = q; p && q == Q; q = nq, p = pa[p]); \
  9. } \
  10. }
  11. int extend(int x) {
  12. if (p = np, q) try_split(np)
  13. else {
  14. for (val[np = ++cnt] = val[p] + 1; p && !q; q = np, p = pa[p]);
  15. if (p) try_split(pa[np]) else pa[np] = 1;
  16. }
  17. return np;
  18. }
  19. #undef q

深度优先搜索,dfs 序,树上基本操作 [#tr01]:

  1. void dfs(int x) {
  2. int i, y; o[++cnt] = x, id[x] = cnt, size[x] = 1;
  3. for (i = first[x]; i; i = next[i])
  4. if ((y = to[i]) != p[x])
  5. p[y] = x, dep[y] = dep[x] + 1, dfs(y), size[x] += size[y];
  6. eid[x] = cnt;
  7. }

最近公共祖先 (LCA) 的倍增算法 (树上倍增的基本模板) [#tr02]:

  1. void dfs(int x) {
  2. int i, y;
  3. for (i = 0; P[i][x]; ++i) P[i + 1][x] = P[i][P[i][x]];
  4. for (i = first[x]; i; i = next[i])
  5. if ((y = to[i]) != p[x])
  6. p[y] = x, dep[y] = dep[x] + 1, dfs(y);
  7. }
  8. int jump_until(int x, int d) {
  9. for (int S = dep[x] - d; S; S &= S - 1) x = P[ctz(S)][x];
  10. return x;
  11. }
  12. int LCA(int x, int y) {
  13. if (dep[x] < dep[y]) std::swap(x, y);
  14. if (x = jump_until(x, dep[y]), x == y) return x;
  15. for (int i = LN - 1; i >= 0; --i)
  16. if (P[i][x] != P[i][y])
  17. x = P[i][x], y = P[i][y];
  18. return p[x];
  19. }

最近公共祖先 (LCA) 的 ST 表算法 [#tr03]:

  1. int cnt = 0, id[N], o[N], st[LN][N];
  2. void dfs(int x, int px = 0) {
  3. int i, y; st[0][cnt] = id[px], o[++cnt] = x, id[x] = cnt;
  4. for (i = first[x]; i; i = next[i])
  5. if ((y = to[i]) != px) dfs(y, x);
  6. }
  7. void build_sparse_table() {
  8. int *f, *g = *st, i, j, k = n - 1;
  9. for (j = 0; 1 << (j + 1) < n; ++j) {
  10. f = g, g = st[j + 1], k -= 1 << j;
  11. for (i = 1; i <= k; ++i)
  12. g[i] = min(f[i], f[i + (1 << j)]);
  13. }
  14. }
  15. inline int LCA_relabel(int x, int y) {
  16. if (x == y) return x;
  17. if (x > y) std::swap(x, y);
  18. int c = lg2(y - x);
  19. return min(st[c][x], st[c][y - (1 << c)]);
  20. }
  21. inline int LCA(int x, int y) {
  22. if (x == y) return x;
  23. int L, R, c; std::tie(L, R) = std::minmax(id[x], id[y]), c = lg2(R - L);
  24. return o[min(st[c][L], st[c][R - (1 << c)])];
  25. }

轻重链剖分 (Heavy-Light Decomposition) [#tr04]:

  1. int p[N], dep[N], size[N];
  2. int cnt = 0, id[N], prf[N], top[N];
  3. void dfs_wt(int x) {
  4. int i, y, &z = prf[x]; size[x] = !next[first[x]];
  5. for (i = first[x]; i; i = next[i])
  6. if ((y = to[i]) != p[x]) {
  7. p[y] = x, dep[y] = dep[x] + 1;
  8. dfs_wt(y), size[x] += size[y];
  9. size[y] > size[z] ? z = y : 0;
  10. }
  11. }
  12. void dfs_hld(int x, int r) {
  13. int i, y; id[x] = ++cnt, top[x] = r;
  14. if (!prf[x]) return;
  15. dfs_hld(prf[x], r);
  16. for (i = first[x]; i; i = next[i])
  17. if (!top[y = to[i]]) dfs_hld(y, y);
  18. }
  19. int solve(int u, int v) {
  20. int x = top[u], y = top[v];
  21. for (; x != y; u = p[x], x = top[u]) {
  22. if (dep[x] < dep[y]) {swap(u, v); swap(x, y);}
  23. // do something on [x, u]
  24. }
  25. if (dep[u] > dep[v]) {swap(u, v); swap(lx, ly);}
  26. // do something on [u, v]
  27. // return something
  28. }

树分治 (静态点分治) [#tr05]:

  1. namespace Centroid {
  2. int V, Gm, G, size[N];
  3. void init(int _V) {V = _V, Gm = INT_MAX;}
  4. int get(int x, int px = 0) {
  5. int i, y, M = 0; size[x] = 1;
  6. for (i = first[x]; i; i = next[i])
  7. if ((y = to[i]) != px && !banned[y])
  8. get(y, x), up(M, size[y]), size[x] += size[y];
  9. return up(M, V - size[x]), M <= Gm ? (Gm = M, G = x) : G;
  10. }
  11. }
  12. #define get_centroid(x, y) (Centroid::init(y), Centroid::get(x))
  13. void dfs(int x, int px = 0, int dep = 1) {
  14. int i, y; size[x] = 1;
  15. for (i = first[x]; i; i = next[i])
  16. if ((y = to[i]) != px && !banned[y])
  17. dfs(y, x, dep + 1), size[x] += size[y];
  18. }
  19. void solve(int x) {
  20. int i, y, G;
  21. banned[x] = true, dfs(x);
  22. // do something
  23. for (i = first[x]; i; i = next[i])
  24. if (!fy[y = to[i]])
  25. G = get_centroid(y, size[y]), solve(G);
  26. }
  27. // main
  28. G = get_centroid(1, n), solve(G);

虚树 (深度栈算法) [#tr06]:

  1. int cnt_vir, vir[N], virp[N];
  2. inline bool idcmp(const int x, const int y) {return id[x] < id[y];}
  3. void DSA(int n, int *v) {
  4. #define ins(x) (virp[x] = stack[top], stack[++top] = vir[cnt_vir++] = x)
  5. int i, x, y, top = 0; cnt_vir = 0;
  6. for (i = 0; i < n; ++i)
  7. if (x = v[i], !top) {
  8. for (; top; --top) stack[top] = 0; ins(x);
  9. } else {
  10. stack[top + 1] = 0;
  11. for (y = LCA(x, stack[top]); dep[ stack[top] ] > dep[y]; --top);
  12. virp[ stack[top + 1] ] = y;
  13. if (stack[top] != y) ins(y); ins(x);
  14. }
  15. for (; top; --top) stack[top] = 0;
  16. std::sort(vir, vir + cnt_vir, idcmp);
  17. }

长链剖分 (Long-Short Decomposition) [#tr07]:

  1. int p[N], dep[N], f[N];
  2. int cnt = 0, id[N], prf[N], top[N];
  3. int len[N], buf[N * 3], *alloc = buf, *near[N];
  4. void dfs_len(int x) {
  5. int i, y, &z = prf[x];
  6. for (i = 0; i < LN && P[i][x]; ++i) P[i + 1][x] = P[i][P[i][x]];
  7. for (i = first[x]; i; i = next[i])
  8. if ((y = to[i]) != p[x]) {
  9. p[y] = x, dep[y] = dep[x] + 1;
  10. dfs_len(y), up(f[x], f[y] + 1);
  11. f[y] > f[z] ? z = y : 0;
  12. }
  13. }
  14. void dfs_lsd(int x, int r, int l = 1) { // long-short decomposition
  15. int i, y; id[x] = ++cnt, top[x] = r;
  16. if (!prf[x]) {len[x] = l; return;}
  17. dfs_lsd(prf[x], r, l + 1), len[x] = len[prf[x]];
  18. for (i = first[x]; i; i = next[i])
  19. if (!top[y = to[i]]) dfs_lsd(y, y);
  20. }
  21. int ancestor(int x, int k) {
  22. if (dep[x] < k) return 0;
  23. if (!k) return x;
  24. x = P[i][x], near[top[x]][dep[x] - dep[top[x]] - (k - (1 << lg2(k)))];
  25. }
  26. void init() {
  27. int i, j, x, *pt;
  28. *f = *dep = -1, dfs_len(1), dfs_lsd(1, 1);
  29. for (i = 1; i < N; ++i)
  30. if (top[i] == i) {
  31. pt = alloc + len[i], alloc += len[i] * 2 + 1, *pt = i;
  32. for (j = 1, x = p[i]; j <= len[i] && x; ++j, x = p[x]) pt[-j] = x;
  33. for (j = 1, x = prf[i]; j <= len[i] && x; ++j, x = prf[x]) pt[j] = x;
  34. }
  35. }
  36. Trie Tree [#tr08]:
  37. int son[N][26], cnt[N], idx;
  38. void insert(char *str)
  39. {
  40. int p = 0;
  41. for (int i = 0; str[i]; i ++ )
  42. {
  43. int u = str[i] - 'a';
  44. if (!son[p][u]) son[p][u] = ++ idx;
  45. p = son[p][u];
  46. }
  47. cnt[p] ++ ;
  48. }
  49. int query(char *str)
  50. {
  51. int p = 0;
  52. for (int i = 0; str[i]; i ++ )
  53. {
  54. int u = str[i] - 'a';
  55. if (!son[p][u]) return 0;
  56. p = son[p][u];
  57. }
  58. return cnt[p];
  59. }

双向邻接表 [#gr01]:

  1. inline void addedge(int u, int v) {
  2. to[++E] = v, next[E] = first[u], first[u] = E;
  3. to[++E] = u, next[E] = first[v], first[v] = E;
  4. }

有向图的强连通分量 [#gr02]:

  1. void dfs(int x) {
  2. int i, y;
  3. id[x] = low[x] = ++cnt, instack[x] = true, sta[stc++] = x;
  4. for(i = first[x]; i; i = next[i])
  5. if (!id[y = to[i]])
  6. dfs(y), down(low[x], low[y]);
  7. else if (instack[y])
  8. down(low[x], id[y]);
  9. if (id[x] == low[x])
  10. for (y = 0; y != x; )
  11. y = sta[--stc], instack[y] = false, top[y] = x;
  12. }

有向无环图的拓扑排序 [#gr03]:

  1. void toposort() {
  2. int i, h, t = 0, x, y;
  3. for (i = 1; i <= V; ++i) if (!deg[i]) que[t++] = i;
  4. for (h = 0; h < t; ++h)
  5. for (i = first[x = que[h]]; i; i = next[i])
  6. if (!--deg[y = to[i]]) que[t++] = y;
  7. }

无向图的桥边 [#gr04]:

  1. void dfs(int x, int px = 0) {
  2. int i, y;
  3. id[x] = low[x] = ++cnt;
  4. for (i = first[x]; i; i = next[i])
  5. if (!id[y = to[i]]) {
  6. dfs(y, i), down(low[x], low[y]);
  7. if (id[x] < low[y]) // edge i is a bridge
  8. } else if (px - 1 ^ i - 1 ^ 1)
  9. down(low[x], id[y]);
  10. }

无向图的割点 [#gr05]:

  1. void dfs(int x, int px = 0) {
  2. int i, y, c = 0; bool is_cut = false;
  3. id[x] = low[x] = ++cnt;
  4. for (i = first[x]; i; i = next[i])
  5. if (!id[y = to[i]]) {
  6. dfs(y, i), down(low[x], low[y]), ++c;
  7. if (id[x] <= low[y]) is_cut = true;
  8. } else if (px - 1 ^ i - 1 ^ 1)
  9. down(low[x], id[y]);
  10. if (!px) is_cut = c > 1;
  11. }

无向图的边双缩点 [#gr06]:

  1. void dfs(int x, int px = 0) {
  2. int i, y;
  3. id[x] = low[x] = ++cnt, stack[stc++] = x;
  4. for (i = first[x]; i; i = next[i])
  5. if (!id[y = to[i]]) {
  6. dfs(y, i), down(low[x], low[y]);
  7. if (id[x] < low[y]) bridge[ad(i)] = bridge[i] = true;
  8. } else if (px - 1 ^ i - 1 ^ 1)
  9. down(low[x], id[y]);
  10. if (id[x] == low[x])
  11. for (y = 0; y != x; )
  12. y = stack[--stc], top[y] = x;
  13. }

无向图的点双缩点 / 圆方树 [#gr07]:

  1. void dfs(int x, int px = 0) {
  2. int i, y, z;
  3. id[x] = low[x] = ++cnt, stack[top++] = x;
  4. for (i = first[x]; i; i = next[i])
  5. if (!id[y = to[i]]) {
  6. dfs(y, i), down(low[x], low[y]);
  7. if (id[x] <= low[y])
  8. for (link(++bcc_cnt + V, x), z = 0; z != y; )
  9. link(z = stack[--top], bcc_cnt + V);
  10. } else if (px - 1 ^ i - 1 ^ 1)
  11. down(low[x], id[y]);
  12. }

带权 edge 结构体 [#gr08]:

  1. struct edge {
  2. int u, v, w;
  3. edge (int u0 = 0, int v0 = 0, int w0 = 0) : u(u0), v(v0), w(w0) {}
  4. };

单源最短路 (Dijkstra) [#gr09]:

  1. typedef std::pair <int, int> pr;
  2. int d[N];
  3. std::priority_queue <pr, std::vector <pr>, std::greater <pr>> pq;
  4. void Dijkstra(int s) {
  5. int i, x, y, D;
  6. memset(d, 63, (V + 1) << 2);
  7. for (pq.emplace(d[s] = 0, s); !pq.empty(); ) {
  8. std::tie(D, x) = pq.top(), pq.pop();
  9. if (d[x] != D) continue;
  10. for (i = first[x]; i; i = next[i])
  11. if (D + e[i].w < d[y = e[i].v])
  12. pq.emplace(d[y] = D + e[i].w, y);
  13. }
  14. }

所有点对的最短路 (Floyd) [#gr10]:

  1. void Floyd() {
  2. int i, j, k;
  3. for (k = 1; k <= V; ++k)
  4. for (i = 1; i <= V; ++i)
  5. for (j = 1; j <= V; ++j)
  6. down(d[i][j], d[i][k] + d[k][j]);
  7. }

最小生成树 (Kruskal) [#gr11]:

  1. struct edge {
  2. int u, v, w;
  3. edge (int u0 = 0, int v0 = 0, int w0 = 0): u(u0), v(v0), w(w0) {}
  4. bool operator < (const edge &b) const {return w < b.w;}
  5. };
  6. void Kruskal(){
  7. uf.resize(V);
  8. sort(e + 1, e + (E + 1));
  9. for(i = 1; i <= E; i++)
  10. if(!uf.test(e[i].u, e[i].v, true)){
  11. // e is an edge of minimum spanning tree
  12. if(++Es >= V - 1) return;
  13. }
  14. }

网络流 edge 结构体 [#gr12]:

  1. struct edge {
  2. int u, v, f; // f is remaining flow
  3. edge(int u0 = 0, int v0 = 0, int f0 = 0): u(u0), v(v0), f(f0) {}
  4. };

最大流 (Dinic) [#gr13]:

  1. namespace Flow {
  2. #define ad(x) ((x - 1 ^ 1) + 1)
  3. const int N = 2000, M = 100000;
  4. struct edge {
  5. int u, v, f;
  6. edge (int u0 = 0, int v0 = 0, int f0 = 0) : u(u0), v(v0), f(f0) {}
  7. } e[M];
  8. int V = 2, E = 0, si = 1, ti = 2, flow;
  9. int first[N], next[M];
  10. int dep[N], cur[N], que[N];
  11. inline void addedge(int u, int v, int f) {
  12. e[++E] = edge(u, v, f), next[E] = first[u], first[u] = E;
  13. e[++E] = edge(v, u), next[E] = first[v], first[v] = E;
  14. }
  15. bool bfs() {
  16. int h, t = 1, i, x, y;
  17. memset(dep, -1, sizeof dep);
  18. que[0] = si, dep[si] = 0;
  19. for (h = 0; h < t; ++h) {
  20. if ((x = que[h]) == ti) return true;
  21. for (i = first[x]; i; i = next[i])
  22. if (dep[y = e[i].v] == -1 && e[i].f)
  23. que[t++] = y, dep[y] = dep[x] + 1;
  24. }
  25. return false;
  26. }
  27. int dfs(int x, int lim) {
  28. int a, c, f = 0;
  29. if (x == ti || !lim) return lim;
  30. for (int &i = cur[x]; i; i = next[i])
  31. if (dep[e[i].v] == dep[x] + 1 && e[i].f) {
  32. a = std::min(lim - f, e[i].f);
  33. c = dfs(e[i].v, a);
  34. e[i].f -= c, e[ad(i)].f += c;
  35. if ((f += c) == lim) return f;
  36. }
  37. return f;
  38. }
  39. int Dinic() {
  40. for (flow = 0; bfs(); flow += dfs(si, INT_MAX))
  41. memcpy(cur, first, sizeof cur);
  42. return flow;
  43. }
  44. }

最小费用最大流 (Dinic) [#gr14]:

  1. namespace CF {
  2. #define ad(x) ((x - 1 ^ 1) + 1)
  3. const int N = 2000, M = 100000, INF = 0x7f7f7f7f;
  4. struct edge {
  5. int u, v, c, f;
  6. edge (int u0 = 0, int v0 = 0, int c0 = 0, int f0 = 0) : u(u0), v(v0), c(c0), f(f0) {}
  7. } e[M];
  8. int V = 2, E = 0, si = 1, ti = 2, flow, cost;
  9. int first[N], next[M];
  10. int dep[N], cur[N], que[M << 1];
  11. bool in_que[N], used[N];
  12. inline void addedge(int u, int v, int c, int f) {
  13. e[++E] = edge(u, v, c, f), next[E] = first[u], first[u] = E;
  14. e[++E] = edge(v, u, -c), next[E] = first[v], first[v] = E;
  15. }
  16. bool bfs() {
  17. int h = M, t = h + 1, i, x, y;
  18. memset(dep, 127, sizeof dep);
  19. que[h] = ti, dep[ti] = 0, in_que[ti] = true;
  20. for (; h < t; ) {
  21. x = que[h++], in_que[x] = false;
  22. for (i = first[x]; i; i = next[i])
  23. if (dep[y = e[i].v] > dep[x] - e[i].c && e[ad(i)].f) {
  24. dep[y] = dep[x] - e[i].c;
  25. if (!in_que[y])
  26. in_que[y] = true, (dep[y] >= dep[que[h]] ? que[t++] : que[--h]) = y;
  27. }
  28. }
  29. return dep[si] < INF;
  30. }
  31. int dfs(int x, int lim) {
  32. int a, c, f = 0;
  33. if (x == ti || !lim) return lim;
  34. used[x] = true;
  35. for (int &i = cur[x]; i; i = next[i])
  36. if (dep[e[i].v] == dep[x] - e[i].c && e[i].f && !used[e[i].v]) {
  37. a = std::min(lim - f, e[i].f);
  38. c = dfs(e[i].v, a);
  39. e[i].f -= c, e[ad(i)].f += c;
  40. if ((f += c) == lim) return f;
  41. }
  42. return f;
  43. }
  44. int Dinic() {
  45. int f;
  46. for (cost = flow = 0; bfs(); ) {
  47. memcpy(cur, first, sizeof cur);
  48. memset(used, 0, sizeof used);
  49. flow += f = dfs(si, INF);
  50. cost += dep[si] * f;
  51. }
  52. return cost;
  53. }
  54. }

二分图最大匹配 (增广路算法) [#gr15]:

  1. bool dfs(int x){
  2. for(int i = 1; i <= n_g; i++)
  3. if(e[x][i] && !used[i]){
  4. used[i] = 1;
  5. if(!boy[i] || dfs(boy[i])){
  6. boy[i] = x; girl[x] = i; return true;
  7. }
  8. }
  9. return false;
  10. }

一般图最大匹配 (带花树算法) [#gr16]:

  1. #define unknown -1
  2. #define boy 0
  3. #define girl 1
  4. int LCA(int x, int y) {
  5. for (++hash_cnt; x; y ? swap(x, y) : (void)0) {
  6. x = ancestor(x);
  7. if (hash[x] == hash_cnt) return x; // visited
  8. hash[x] = hash_cnt;
  9. x = prev[match[x]];
  10. }
  11. return 0x131a371;
  12. }
  13. void blossom(int x, int y, int root, int &t) { // vertices in blossoms are all boys !
  14. for (int z; ancestor(x) != root; y = z, x = prev[y]) {
  15. prev[x] = y; z = match[x];
  16. if (col[z] == girl) que[t++] = z, col[z] = boy;
  17. if (ancestor(x) == x) p[x] = root;
  18. if (ancestor(z) == z) p[z] = root;
  19. }
  20. }
  21. bool bfs(int st) {
  22. int h, t = 1, i, x, y, b, g;
  23. que[0] = st; col[st] = boy;
  24. for (h = 0; h < t; ++h)
  25. for (i = first[x = que[h]]; i; i = next[i])
  26. if (col[y = to[i]] == unknown) { // common step
  27. prev[y] = x; col[y] = girl;
  28. if (!match[y]) { // augment (change mates) !!!
  29. for (g = y; g; swap(match[b], g))
  30. match[g] = b = prev[g];
  31. return true;
  32. }
  33. col[que[t++] = match[y]] = boy;
  34. } else if(col[y] == boy && ancestor(x) != ancestor(y)) { // flower !!!
  35. b = LCA(x, y); blossom(x, y, b, t); blossom(y, x, b, t);
  36. }
  37. return false;
  38. }
  39. // main process
  40. for (i = 1; i <= V; ++i) {
  41. for (v = 1; v <= V; ++v) col[v] = unknown, p[v] = v;
  42. if (!match[i] && bfs(i)) ++ans;
  43. }

最小树形图 (朱-刘-Edmonds) [#gr17]:

  1. namespace DMST {
  2. const int N = 108, M = 10054, INF = 0x3f3f3f3f;
  3. int V, E, r;
  4. int p[N], best[N];
  5. int bel[N], used[N], cyc[N];
  6. int min[N], delta[M];
  7. bool ans[M];
  8. edge e[M];
  9. pr elim[N * M];
  10. inline void reset(int n, int root) {V = n, E = 0, r = root;}
  11. inline void link(int u, int v, int w) {e[E++] = edge(u, v, w);}
  12. int CLE() {
  13. int i, u, v, w, n, r, cnt, tot = 0, w0 = 0, w1 = 0;
  14. n = V, r = DMST::r, std::iota(bel, bel + (V + 1), 0);
  15. memset(ans, false, E), memset(delta, 0, E << 2);
  16. for (; ; n = cnt, r = cyc[r]) {
  17. memset(min, 63, (V + 1) << 2),
  18. memset(used, 0, (V + 1) << 2), used[r] = -1;
  19. memset(cyc, cnt = 0, (V + 1) << 2);
  20. for (i = 0; i < E; ++i) {
  21. u = bel[ e[i].u ], v = bel[ e[i].v ], w = e[i].w - delta[i];
  22. if (u != v && w < min[v]) p[v] = u, min[v] = w, best[v] = i;
  23. }
  24. for (i = 1; i <= n; ++i) if (i != r) {
  25. if (min[i] >= INF) return -1;
  26. for (u = i; !(u == r || used[u]); u = p[u]) used[u] = i;
  27. if (used[u] == i) {
  28. ++cnt, v = u;
  29. do cyc[v] = cnt, v = p[v]; while (v != u);
  30. }
  31. }
  32. if (!(w = cnt)) break;
  33. for (i = 1; i <= n; ++i)
  34. if (cyc[i]) ans[ best[i] ] = true;
  35. else cyc[i] = ++cnt;
  36. for (i = 0; i < E; ++i) {
  37. u = bel[ e[i].u ], v = bel[ e[i].v ];
  38. if (cyc[u] != cyc[v])
  39. if (delta[i] += min[v], cyc[v] <= w)
  40. elim[tot++] = pr(best[v], i);
  41. }
  42. for (i = 1; i <= V; ++i) bel[i] = cyc[bel[i]];
  43. }
  44. for (i = 1; i <= n; ++i) if (i != r) ans[ best[i] ] = true;
  45. for (i = tot - 1; i >= 0; --i) if (ans[elim[i].second]) ans[elim[i].first] = false;
  46. for (i = 0; i < E; ++i) if (ans[i]) ++w0, w1 += e[i].w;
  47. return assert(w0 == V - 1), w1;
  48. }
  49. }

并查集 (不封装,按秩合并) [#ds01]:

  1. int ancestor(int x) {return p[x] == x ? x : (p[x] = ancestor(p[x]));}
  2. bool test(int x, int y, bool un = false) {
  3. if ((x = ancestor(x)) == (y = ancestor(y))) return true;
  4. if (un) size[x] > size[y] ? std::swap(x, y) : (void)0, p[x] = y, size[y] += size[x];
  5. return false;
  6. }

并查集 (封装) [#ds02]:

  1. struct UFind{
  2. int sz, *p;
  3. UFind (): sz(0) {p = NULL;}
  4. ~UFind () {if(p) delete [] (p);}
  5. void resize(int size){
  6. if(p) delete [] (p); p = new int[(sz = size) + 1];
  7. for(int i = 0; i <= sz; i++) p[i] = i;
  8. }
  9. int ancestor(int x) {return x == p[x] ? x : p[x] = ancestor(p[x]);}
  10. bool test(int x, int y, bool un = false){
  11. if((x = ancestor(x)) == (y = ancestor(y))) return true;
  12. if(un) p[x] = y; return false;
  13. }
  14. };

树状数组 (不封装) [#ds03]:

  1. #define lowbit(x) (x & -x)
  2. int sum(int h){
  3. int s = 0;
  4. while(h){
  5. s += a[h];
  6. h -= lowbit(h);
  7. }
  8. return s;
  9. }
  10. int add(int h, int v){
  11. while(h <= n){
  12. a[h] += v;
  13. h += lowbit(h);
  14. }
  15. return v;
  16. }

树状数组 (封装,可清空) [#ds04]:

  1. struct BIT {
  2. #define lowbit(x) (x & -x)
  3. int n, ti, tag[N]; ll x[N];
  4. BIT () : ti(0) {}
  5. inline void resize(int size) {n = size;}
  6. inline void clear() {++ti;}
  7. inline ll & recover(int id) {return tag[id] == ti ? x[id] : (tag[id] = ti, x[id] = 0);}
  8. ll sum(int h) {ll s = 0; for (; h > 0; h -= lowbit(h)) s += recover(h); return s;}
  9. void add(int h, ll v) {for (; h <= n; h += lowbit(h)) recover(h) += v;}
  10. };

线段树 (不封装) [#ds05]:

  1. #define segc int M = L + R - 1 >> 1, lc = id << 1, rc = lc | 1
  2. void add(int id, int L, int R, int h, int v){
  3. if(L == R) return void(st[id] += v);
  4. segc; h <= M ? add(lc, L, M, h, v) : add(rc, M + 1, R, h, v);
  5. x[id].v = x[lc].v + x[rc].v;
  6. }
  7. int range(int id, int L, int R, int ql, int qr){
  8. if(ql <= L && qr >= R) return st[id];
  9. segc, s = 0;
  10. if(ql <= M) s += range(lc, L, M, ql, min(qr, M));
  11. if(qr > M) s += range(rc, M + 1, R, max(ql, M + 1), qr);
  12. return s;
  13. }

线段树 (封装) [#ds06]:

  1. struct ST{
  2. #define segc int M = L + R - 1 >> 1, lc = id << 1, rc = lc | 1
  3. int sz;
  4. struct node {int v, f; bool zero;} *x;
  5. ST (): sz(0) {x = NULL;}
  6. ~ST () {if(x) delete [] (x);}
  7. void resize(int size) {sz = size; int sz0 = sz << 3; if(x) delete [] (x);
  8. x = new node[sz0]; memset(x, 0, sz0 * sizeof(node));}
  9. void add(int h, int v) {add(1, 1, sz, h, v);}
  10. int range(int l, int r) {return query(1, 1, sz, l, r);}
  11. void add(int id, int L, int R, int h, int v){
  12. if(L == R) return void(x[id].v += v);
  13. segc; h <= M ? add(lc, L, M, h, v) : add(rc, M + 1, R, h, v);
  14. x[id].v = x[lc].v + x[rc].v;
  15. }
  16. int query(int id, int L, int R, int ql, int qr){
  17. if(ql <= L && R <= qr) return x[id].v;
  18. segc, s = 0;
  19. if(ql <= M) s += query(lc, L, M, ql, min(qr, M));
  20. if(qr > M) s += query(rc, M + 1, R, max(ql, M + 1), qr);
  21. return s;
  22. }
  23. };

可持久化线段树 (add 操作) [#ds07]:

  1. int add(int _id, int L, int R, int h, int v){
  2. int id = ++cnt; x[id] = x[_id]; x[id].v += v;
  3. if(L == R) return id;
  4. int M = L + R - 1 >> 1;
  5. if(h <= M) x[id].lc = add(x[id].lc, L, M, h, v);
  6. else x[id].rc = add(x[id].rc, M + 1, R, h, v);
  7. return id;
  8. }

伸展树 (Splay) [#ds08]:

  1. #define pa p[nd]
  2. #define root nd[0].c[0]
  3. struct node {int v, sz, p, c[2]; ll sum;} nd[N];
  4. inline int dir(int x) {return x == x[nd].pa.c[1];}
  5. inline void update(int x){
  6. x[nd].sz = x[nd].c[0][nd].sz + x[nd].c[1][nd].sz + 1;
  7. x[nd].sum = x[nd].c[0][nd].sum + x[nd].c[1][nd].sum + x[nd].v;
  8. }
  9. void rotate(int x){
  10. int y = x[nd].p, d = !dir(x);
  11. nd[y[nd].c[!d] = x[nd].c[d]].p = y;
  12. x[nd].p = y[nd].p;
  13. y[nd].pa.c[dir(y)] = x;
  14. nd[x[nd].c[d] = y].p = x;
  15. update(y);
  16. }
  17. void splay(int x, int g = 0){
  18. for(; x[nd].p != g; rotate(x))
  19. if(x[nd].pa.p != g) rotate(dir(x) ^ dir(x[nd].p) ? x : x[nd].p);
  20. update(x);
  21. }
  22. void insert(int x){
  23. int y = 0, d = 0;
  24. if(root) for(y = root; d = (val[x] < y[nd].v), y[nd].c[d]; y = y[nd].c[d]);
  25. y[nd].c[d] = x;
  26. 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;
  27. splay(x);
  28. }
  29. void erase(int x){
  30. if(x[nd].p) splay(x);
  31. if(!(x[nd].c[0] && x[nd].c[1])){
  32. int d = (x[nd].c[1] > 0);
  33. x[nd].c[d][nd].p = 0;
  34. root = x[nd].c[d];
  35. }else{
  36. int y;
  37. for(y = x[nd].c[1]; y[nd].c[0]; y = y[nd].c[0]);
  38. splay(y, x);
  39. nd[y[nd].c[0] = x[nd].c[0]].p = y;
  40. y[nd].p = 0; root = y;
  41. update(y);
  42. }
  43. }
  44. int kth(int x, int v){
  45. if(x[nd].sz < v) return -1;
  46. for(int j; ; ){
  47. j = x[nd].c[0][nd].sz;
  48. if(v == j + 1) return x;
  49. x = x[nd].c[v > j]; v > j ? (v -= j + 1) : v;
  50. }
  51. }

动态树 (Link-Cut Tree) [#ds09]:

  1. namespace LCT {
  2. #define pa p[nd]
  3. struct node {bool rev; int v, p, c[2];} nd[N];
  4. 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;}
  5. inline void set(int x, int px, int c) {if (nd[x].p = px, ~c) nd[px].c[c] = x;}
  6. inline void reverse(int x) {x && (std::swap(nd[x].c[0], nd[x].c[1]), nd[x].rev = !nd[x].rev);}
  7. void push_down(int x) {if (nd[x].rev) reverse(nd[x].c[0]), reverse(nd[x].c[1]), nd[x].rev = false;}
  8. void pull_down(int x) {if (~dir(x)) pull_down(nd[x].p); push_down(x);}
  9. 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);}
  10. void rotate(int x) {int y = nd[x].p, d = !dir(x); set(nd[x].c[d], y, !d), set(x, nd[y].p, dir(y)), set(y, x, d);}
  11. 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);}
  12. void access(int x) {for (int y = 0; x; y = x, x = nd[x].p) splay(x), nd[x].c[1] = y, update(x);}
  13. void make_root(int x) {access(x), splay(x), reverse(x);}
  14. 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;}
  15. int split(int x, int y) {return make_root(x), access(y), splay(y), y;}
  16. void link(int x, int y) {make_root(x), nd[x].p = y;}
  17. void cut(int x, int y) {split(x, y), nd[x].p = nd[y].c[0] = 0, update(y);}
  18. void trylink(int x, int y) {x == y || (split(x, y), ~dir(x)) || (nd[x].p = y);}
  19. 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);}
  20. }

树堆 (Treap) [#ds10]:

  1. struct random_t{
  2. ull seed;
  3. static const ull multiplier = 0x5deece66dll;;
  4. static const ull addend = 0xbll;
  5. static const ull mask = 0xffffffffffffll;
  6. random_t () {char *x = new char; seed = (ull)x; delete x;}
  7. unsigned int next(){
  8. seed = (seed * multiplier + addend) & mask;
  9. return seed >> 16;
  10. }
  11. unsigned int next(unsigned int n){
  12. return n * (ull)next() >> 32;
  13. }
  14. }rnd;
  15. #define pa p[nd]
  16. #define C(x) c[x][nd]
  17. #define root nd[0].c[0]
  18. struct node {int v, sz, pt; int c[2], p; unsigned priority;} nd[N];
  19. int cnt = 0;
  20. inline int dir(int x) {return x == nd[x].pa.c[1];}
  21. inline void update(int x){
  22. nd[x].sz = nd[x].C(0).sz + nd[x].C(1).sz + nd[x].pt;
  23. }
  24. void rotate(int x){
  25. int y = nd[x].p, d = !dir(x);
  26. nd[nd[y].c[!d] = nd[x].c[d]].p = y;
  27. nd[x].p = nd[y].p;
  28. nd[y].pa.c[dir(y)] = x;
  29. nd[nd[x].c[d] = y].p = x;
  30. update(y); update(x);
  31. }
  32. void push_up(int x) {for(; x; x = nd[x].p) update(x);}
  33. void rotation(int x) {for(; nd[x].p && nd[x].priority < nd[x].pa.priority; ) rotate(x);}
  34. void insert(int v){
  35. int x = 0, y = 0, d = 0;
  36. if(root) for(y = root; nd[y].v != v && nd[y].c[d = v > nd[y].v]; y = nd[y].c[d]);
  37. if(nd[y].v == v) {++nd[y].pt; push_up(y); return;}
  38. nd[y].c[d] = x = ++cnt;
  39. nd[x].v = v; nd[x].sz = nd[x].pt = 1; nd[x].p = y; nd[x].c[0] = nd[x].c[1] = 0;
  40. nd[x].priority = rnd.next(); push_up(y);
  41. rotation(x);
  42. }
  43. void erase(int v){
  44. int x = 0, y = 0, d = 0;
  45. if(root) for(x = root; nd[x].v != v && nd[x].c[d = v > nd[x].v]; x = nd[x].c[d]);
  46. if(nd[x].v != v) return;
  47. if(nd[x].pt > 1) {--nd[x].pt; push_up(x); return;}
  48. for(; nd[x].c[0] && nd[x].c[1]; rotate(nd[x].c[d]))
  49. d = nd[x].C(0).priority > nd[x].C(1).priority;
  50. d = nd[x].c[1] > 0; y = nd[x].c[d];
  51. nd[y].p = nd[x].p; nd[x].pa.c[dir(x)] = y; push_up(nd[y].p);
  52. }
  53. int rank(int v){
  54. int x = 0, d = 0, k = 0;
  55. if(root) for(x = root; nd[x].v != v && nd[x].c[d = v > nd[x].v]; x = nd[x].c[d])
  56. if(d) k += nd[x].C(0).sz + nd[x].pt;
  57. if(nd[x].v != v) return -1;
  58. return k + nd[x].C(0).sz;
  59. }
  60. int kth(int k){
  61. int x = root;
  62. if(nd[x].sz < k) return -1;
  63. for(int j, z; ; ){
  64. j = nd[x].C(0).sz; z = nd[x].pt;
  65. if(j <= k && k < j + z) return x;
  66. x = nd[x].c[k > j]; k > j ? (k -= j + z) : k;
  67. }
  68. }
  69. int prev(int v){
  70. int x = 0, r = -1, d = 0;
  71. if(root) for(x = root; x; x = nd[x].c[d]) if(d = v > x[nd].v) up(r, nd[x].v); // too little
  72. return r;
  73. }
  74. int succ(int v){
  75. int x = 0, r = INT_MAX, d = 0;
  76. if(root) for(x = root; x; x = nd[x].c[d]) if(!(d = v >= x[nd].v)) down(r, nd[x].v); // too large
  77. return r;
  78. }

析合树 (构造) [#ds11]:

  1. int n, p[N];
  2. namespace DCTree {
  3. typedef std::pair <int, int> pr;
  4. const int N = ::N * 2;
  5. enum type {leaf, disjunct, conjunct} I[N];
  6. pr st[20][N];
  7. int stack1[N], stack2[N], stack[N];
  8. int cnt, root, left[N], mid[N], right[N];
  9. 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;}
  10. void build_sparse_table() {
  11. int i, j, k = n; pr *f, *g = *st;
  12. for (j = 0; 1 << (j + 1) <= n; ++j) {
  13. f = g, g = st[j + 1], k -= 1 << j;
  14. for (i = 1; i <= k; ++i)
  15. up(g[i] = f[i], f[i + (1 << j)]);
  16. }
  17. }
  18. inline bool is_consecutive(int L, int R) {
  19. int c = lg2(R - L); pr ans = st[c][L]; up(ans, st[c][R - (1 << c)]);
  20. return ans.second - ans.first == R - L - 1;
  21. }
  22. namespace ST {
  23. #define segc int M = (L + R - 1) >> 1, lc = id << 1, rc = lc | 1
  24. struct node {int v, tag;} x[N * 4];
  25. void build(int id, int L, int R) {
  26. x[id].v = L, x[id].tag = 0;
  27. if (L == R) return;
  28. segc; build(lc, L, M), build(rc, M + 1, R);
  29. }
  30. void add(int id, int L, int R, int ql, int qr, int v) {
  31. if (ql <= L && R <= qr) {x[id].v += v, x[id].tag += v; return;}
  32. segc;
  33. if (ql <= M) add(lc, L, M, ql, qr, v);
  34. if (qr > M) add(rc, M + 1, R, ql, qr, v);
  35. x[id].v = std::min(x[lc].v, x[rc].v) + x[id].tag;
  36. }
  37. int find_suf(int id, int L, int R, int v, int cv = 0) {
  38. if (cv + x[id].v > v) return -1;
  39. if (L == R) return L;
  40. segc, p = find_suf(lc, L, M, v, cv += x[id].tag);
  41. return ~p ? p : find_suf(rc, M + 1, R, v, cv);
  42. }
  43. }
  44. int pa[N], fc[N], nc[N], deg[N];
  45. inline void link(int x, int px) {pa[x] = px, nc[x] = fc[px], fc[px] = x, ++deg[px];}
  46. void build() {
  47. int i, l, top1 = 0, top2 = 0, top = 0, &v = root, u; cnt = n;
  48. for (i = 1; i <= n; ++i) st[0][i] = pr(p[i], p[i]), left[i] = right[i] = i, I[i] = leaf;
  49. build_sparse_table(), ST::build(1, 1, n);
  50. for (i = 1; i <= n; ++i) {
  51. for (; top1 && p[i] > p[ stack1[top1] ]; --top1)
  52. ST::add(1, 1, n, stack1[top1 - 1] + 1, stack1[top1], p[i] - p[ stack1[top1] ]);
  53. for (; top2 && p[i] < p[ stack2[top2] ]; --top2)
  54. ST::add(1, 1, n, stack2[top2 - 1] + 1, stack2[top2], p[ stack2[top2] ] - p[i]);
  55. stack1[++top1] = stack2[++top2] = i;
  56. l = ST::find_suf(1, 1, n, i);
  57. for (v = i; top && left[ u = stack[top] ] >= l; --top)
  58. if (I[u] == conjunct && is_consecutive(mid[u], i + 1))
  59. right[u] = i, link(v, u), v = u;
  60. else if (is_consecutive(left[u], i + 1)) {
  61. I[++cnt] = conjunct, link(u, cnt), link(v, cnt);
  62. left[cnt] = left[u], right[cnt] = i, mid[cnt] = left[v], v = cnt;
  63. } else {
  64. I[++cnt] = disjunct, link(v, cnt);
  65. for (; top && !is_consecutive(left[ u = stack[top] ], i + 1); --top)
  66. link(u, cnt); link(u, cnt);
  67. left[cnt] = left[u], right[cnt] = i, v = cnt;
  68. }
  69. stack[++top] = v;
  70. }
  71. }
  72. }

Chtholly 树 (ODT) / set 维护连续段 [#ds12]:

  1. namespace CTree {
  2. map C;
  3. map::iterator split(int pos) {
  4. map::iterator it = C.lower_bound(pos), jt = it;
  5. return it->first == pos ? it : C.emplace_hint(it, pos, (--jt)->second);
  6. }
  7. void modify(int l, int r, int v) {
  8. map::iterator it = split(l), jt = split(r), i, j;
  9. for (j = it; (i = j++) != jt; ) // do something on [i, j]
  10. C.erase(it, jt), C.emplace(l, v); // do something
  11. }
  12. }

可删除的堆 [#ds13]:

  1. struct heap {
  2. std::priority_queue <int, std::vector <int>, std::greater <int>> A, B;
  3. inline void emplace(int x) {A.emplace(x);}
  4. inline void erase(int x) {B.emplace(x);}
  5. inline void normalize() {for (; !B.empty() && A.top() == B.top(); A.pop(), B.pop());}
  6. inline int top() {return normalize(), A.empty() ? INF : A.top();}
  7. inline bool pop() {return normalize(), !A.empty() && (A.pop(), true);}
  8. inline void clear() {for (; !A.empty(); A.pop()); for (; !B.empty(); B.pop());}
  9. };

IO 优化 [#ed01]:

  1. #define ID isdigit(c = *next++)
  2. #define IS isspace(c = *next++)
  3. struct Istream {
  4. char *next, buf[20030731];
  5. Istream & init(FILE *f = stdin) {fread(buf, 1, sizeof buf, f); next = buf; return *this;}
  6. Istream & operator >> (int &x) {
  7. int c; x = 0;
  8. for (; !ID; ) if (!~c) return *this;
  9. for (x = c & 15; ID; x = x * 10 + (c & 15));
  10. return *this;
  11. }
  12. Istream & operator >> (char *x) {
  13. int c;
  14. for (; IS; ) if (!~c) return *this;
  15. for (*x++ = c; !IS; *x++ = c) if (!~c) break;
  16. return *x = 0, *this;
  17. }
  18. char get() {return *next++;}
  19. } cin;
  20. struct Ostream {
  21. char *next, buf[20030731], _buf[34];
  22. Ostream () {next = buf;}
  23. void flush(FILE *f = stdout) {fwrite(buf, 1, next - buf, f); next = buf;}
  24. Ostream & operator << (int x) {
  25. if (!x) return put(48), *this;
  26. int i;
  27. for (i = 0; x; x /= 10) _buf[++i] = x % 10 | 48;
  28. for (; i; --i) put(_buf[i]);
  29. return *this;
  30. }
  31. Ostream & operator << (char c) {return put(c), *this;}
  32. Ostream & operator << (const char *s) {for (char *p = (char*)s; *p; ++p) put(*p); return *this;}
  33. void put(char c) {*next++ = c;}
  34. } cout;

动态规划的转移 [#ed02]:

  1. inline void up(int &x, const int y) {x < y ? x = y : 0;}
  2. inline void down(int &x, const int y) {x > y ? x = y : 0;}
  3. inline int min(const int x, const int y) {return x < y ? x : y;}
  4. inline int max(const int x, const int y) {return x < y ? y : x;}
  5. inline int & reduce(int &x) {return x += x >> 31 & mod;}
  6. inline void add(int &x, const int y) {x += y - mod, x += x >> 31 & mod;}
  7. inline void sub(int &x, const int y) {x -= y, x += x >> 31 & mod;}
  8. inline int & half(int &x) {return x = (x >> 1) + (-(x & 1) & iv2);}
  9. inline int & neg(int &x) {return x = (!x - 1) & (mod - x);}
  10. // another ver.
  11. inline bool up(int &x, const int y) {return x < y ? x = y, 1 : 0;}
  12. inline bool down(int &x, const int y) {return x > y ? x = y, 1 : 0;}
  13. inline int & add(int &x, const int y) {return x += y - mod, x += x >> 31 & mod;}
  14. inline int & sub(int &x, const int y) {return x -= y, x += x >> 31 & mod;}
  15. // templated ver.
  16. #define templated template <typename T>
  17. inline bool up(T &x, const T y) {return x < y ? x = y, 1 : 0;}
  18. inline bool down(T &x, const T y) {return x > y ? x = y, 1 : 0;}
  19. inline T min(const T x, const T y) {return x < y ? x : y;}
  20. inline T max(const T x, const T y) {return x < y ? y : x;}

乘模函数 (64 bit 大整数相乘取模) [#ed03]:

  1. inline ll MulMod(ll a, ll b, ll m) {
  2. ll t = (a * b - (ll)((ld)a * b / m) * m) % m;
  3. return t + (t >> 63 & m);
  4. }

ST 表 [#ed04]:

  1. namespace RMQ_simple {
  2. void build_sparse_table() {
  3. int *f, *g = *st, i, j, k = n;
  4. for (j = 0; 1 << (j + 1) <= n; ++j) {
  5. f = g, g = st[j + 1], k -= 1 << j;
  6. for (i = 0; i < k; ++i)
  7. g[i] = min(f[i], f[i + (1 << j)]);
  8. }
  9. }
  10. inline int range(int L, int R) {
  11. int c = lg2(R - L);
  12. return min(st[c][L], st[c][R - (1 << c)]);
  13. }
  14. }
  15. namespace RMQ_fake {
  16. const int LN = 18, TH = 18;
  17. int n, *a, pre[N], suf[N], bel[N];
  18. int L, st[LN][N / TH], *lay = *st;
  19. void build(int n_, int *a_) {
  20. int i, j, k, I, *f, *g = lay; n = n_, a = a_;
  21. for (I = i = 0; I < n; ++i, I += TH) {
  22. pre[I] = a[I], bel[I] = i;
  23. for (j = 1; j < TH && I + j < n; ++j) pre[I + j] = min(pre[I + j - 1], a[I + j]), bel[I + j] = i;
  24. for (--j, suf[I + j] = a[I + j]; --j >= 0; suf[I + j] = min(suf[I + j + 1], a[I + j]));
  25. lay[i] = suf[I];
  26. }
  27. for (k = L = i, j = 0; 1 << (j + 1) <= L; ++j)
  28. for (f = g, g = st[j + 1], k -= 1 << j, i = 0; i < k; ++i)
  29. g[i] = min(f[i], f[i + (1 << j)]);
  30. }
  31. inline int range(int L, int R) {
  32. if (R <= L + TH) return *std::min_element(a + L, a + R);
  33. int x = bel[L] + 1, y = bel[--R], c = lg2(y - x);
  34. return min(min(suf[L], pre[R]), x < y ? min(st[c][x], st[c][y - (1 << c)]) : INT_MAX);
  35. }
  36. }

离散化 [#ed05]:

  1. namespace DC {
  2. int F[N]; pr D[N];
  3. int Discretize(int n) {
  4. int i, cnt = 0; std::sort(D, D + n);
  5. for (i = 0; i < n; ++i)
  6. F[D[i].second] = (i && D[i].first == D[i - 1].first ? cnt - 1 : (D[cnt] = D[i], cnt++));
  7. return cnt;
  8. }
  9. }
  10. Hash Map [#ed06]:
  11. class hash_map{
  12. public:
  13. static const int HASH_MAX = 0xffffff, N = 8000000;
  14. int cnt, first[HASH_MAX + 2], next[N]; data z[N];
  15. inline int getHash(int key) {return (key ^ key << 3 ^ key >> 2) & HASH_MAX;}
  16. void clear() {for(; cnt > 0; --cnt) first[z[cnt].hash] = 0;}
  17. data * find(int key, bool inserted){
  18. int x = getHash(key), i;
  19. for(i = first[x]; i; i = next[i]) if(z[i].key == key) return z + i;
  20. if(!inserted) return NULL;
  21. z[++cnt] = data(key, 0, x); next[cnt] = first[x]; first[x] = cnt;
  22. return z + cnt;
  23. }
  24. };

快速 Fourier 变换 (Fast Fourier Transform) [#ed07]:

  1. // 'Fast Number Theory Transform' is in memos/12.html.
  2. typedef std::complex <double> C;
  3. namespace rpoly_base {
  4. int l, n; double iv; C w2[N];
  5. void init(int n = N) {
  6. int i, t = min(n > 1 ? lg2(n - 1) : 0, 21); double angle = pi;
  7. for (*w2 = C(1), i = 0; i <= t; ++i) w2[1 << i] = std::polar(1., angle *= .5);
  8. for (i = 3; i < n; ++i) if (i & (i - 1)) w2[i] = w2[i & (i - 1)] * w2[i & -i];
  9. }
  10. inline void FFT_init(int len) {n = 1 << (l = len), iv = 1. / n;}
  11. void DIF(C *a) {
  12. int i, len = n >> 1; C *j, *k, *o, R;
  13. for (i = 0; i < l; ++i, len >>= 1)
  14. for (j = a, o = w2; j != a + n; j += len << 1, ++o)
  15. for (k = j; k != j + len; ++k)
  16. R = *o * k[len], k[len] = *k - R, *k += R;
  17. }
  18. void DIT(C *a) {
  19. int i, len = 1; C *j, *k, *o, R;
  20. for (i = 0; i < l; ++i, len <<= 1)
  21. for (j = a, o = w2; j != a + n; j += len << 1, ++o)
  22. for (k = j; k != j + len; ++k)
  23. R = *k + k[len], k[len] = (*k - k[len]) * *o, *k = R;
  24. }
  25. }
  26. namespace rpoly {
  27. using namespace rpoly_base;
  28. C B1[N], B2[N], B3[N], B4[N];
  29. void mulf(int A, int B, double *a, double *b, double *c) {
  30. if (!(A || B)) {*c = *a * *b; return;}
  31. int i; FFT_init(lg2(A + B) + 1);
  32. for (i = 0; i <= A; ++i) B1[i] = C(a[i]); memset(B1 + i, 0, (n - i) << 4);
  33. for (i = 0; i <= B; ++i) B2[i] = C(b[i]); memset(B2 + i, 0, (n - i) << 4);
  34. DIF(B1), DIF(B2);
  35. for (i = 0; i < n; ++i) B1[i] *= B2[i];
  36. DIT(B1), std::reverse(B1 + 1, B1 + n);
  37. for (i = 0; i <= A + B; ++i) c[i] = B1[i].real() * iv;
  38. }
  39. void muli(int A, int B, int *a, int *b, int *c) {
  40. if (!(A || B)) {*c = (ll)*a * *b % mod; return;}
  41. int i, j, k; FFT_init(lg2(A + B) + 1);
  42. for (i = 0; i <= A; ++i) B1[i] = C(a[i] & 32767, a[i] >> 15); memset(B1 + i, 0, (n - i) << 4);
  43. for (i = 0; i <= B; ++i) B2[i] = C(b[i] & 32767, b[i] >> 15); memset(B2 + i, 0, (n - i) << 4);
  44. DIF(B1), DIF(B2);
  45. *B3 = B1->real() * *B2, *B4 = B1->imag() * *B2;
  46. for (k = 0; k < l; ++k)
  47. for (i = 1 << k, j = (2 << k) - 1; i < 2 << k; ++i, --j)
  48. B3[j] = (B1[i] + std::conj(B1[j])) * B2[i] * C(.5, 0.),
  49. B4[j] = (B1[i] - std::conj(B1[j])) * B2[i] * C(0., -.5);
  50. DIT(B3), DIT(B4);
  51. for (i = 0; i <= A + B; ++i)
  52. c[i] = (ll(B3[i].real() * iv + .5) + (ll((B3[i].imag() + B4[i].real()) * iv + .5) % mod << 15) + (ll(B4[i].imag() * iv + .5) % mod << 30) + mod) % mod;
  53. }
  54. }

Gauss 消元法 [#ed08]:

  1. // Gauss elimination with type 'double'
  2. struct LnEqn{
  3. int sz;
  4. double **m, *b;
  5. LnEqn (): sz(0) {m = NULL; b = NULL;}
  6. void resize(int size){
  7. sz = size; m = new double *[sz];
  8. for(int i = 0; i < sz; i++){
  9. m[i] = new double[sz];
  10. memset(m[i], 0, sz << 3);
  11. }
  12. b = new double[sz];
  13. memset(b, 0, sz << 3);
  14. }
  15. ~LnEqn (){
  16. if(m) {for(int i = 0; i < sz; i++) delete [] (m[i]); delete [] (m);}
  17. if(b) delete [] (b);
  18. }
  19. bool solve(){
  20. int i, j, k, maxi; double coe;
  21. for(k = 0; k < sz; k++){
  22. maxi = k;
  23. for(i = k + 1; i < sz; i++)
  24. if(fabs(m[i][k]) > fabs(m[maxi][k]))
  25. maxi = i;
  26. if(fabs(m[maxi][k]) < 1e-8) return false;
  27. if(maxi != k){
  28. swap(m[maxi], m[k]);
  29. swap(b[maxi], b[k]);
  30. }
  31. coe = 1.0 / m[k][k];
  32. for(j = 0; j < sz; j++)
  33. m[k][j] *= coe;
  34. m[k][k] = 1.0;
  35. b[k] *= coe;
  36. for(i = 0; i < sz; i++){
  37. if(i == k) continue;
  38. coe = m[i][k];
  39. for(j = 0; j < sz; j++)
  40. m[i][j] -= coe * m[k][j];
  41. m[i][k] = 0.0;
  42. b[i] -= coe * b[k];
  43. }
  44. }
  45. return true;
  46. }
  47. };

线性规划 (xₚ ≥ 0, bₚ ≥ 0) [#ed09]:

  1. const double eps = 1e-8;
  2. int id[N + E];
  3. double m[E][N], b[E], *c = m[0], ans[N + E];
  4. void pivot(int toFree, int toBasic); // basic(1,m) -> free, free(1,n) -> basic
  5. void pivot(int r, int c){
  6. int i, j; double coe = 1.0 / m[r][c];
  7. swap(id[n + r], id[c]);
  8. m[r][c] = 1.0;
  9. for(j = 1; j <= n; ++j)
  10. m[r][j] *= coe;
  11. b[r] *= coe;
  12. for(i = 0; i <= e; ++i){
  13. if(i == r) continue;
  14. coe = m[i][c]; m[i][c] = 0.0;
  15. for(j = 1; j <= n; ++j)
  16. m[i][j] -= coe * m[r][j];
  17. b[i] -= coe * b[r];
  18. }
  19. }
  20. bool simplex(){
  21. int i, j, basic, free; double G;
  22. for(; ; ){
  23. basic = free = 0; G = INFINITY;
  24. for(i = 1; i <= n; ++i) // free (nonbasic) variable
  25. if(c[i] > c[free]) free = i;
  26. if(!free) return true;
  27. for(j = 1; j <= e; ++j) // basic variable
  28. if(m[j][free] > eps && b[j] < G * m[j][free]){
  29. G = b[j] / m[j][free]; basic = j;
  30. }
  31. if(!basic) return puts("Unbounded"), false;
  32. pivot(basic, free);
  33. }
  34. }
  35. // initialize :
  36. for(j = 1; j <= n + e; ++j) id[j] = j;
  37. c[0] = eps;
  38. // output:
  39. if(simplex()){
  40. printf("%.8lg\n", -*b);
  41. for(i = 1; i <= e; ++i) ans[id[n + i]] = b[i];
  42. for(j = 1; j <= n; ++j) printf("%.8lg%c", ans[j], j == n ? 10 : 32);
  43. }

Gauss 消元求行列式 (模意义) [#ed10]:

  1. int gauss(int n) {
  2. int i, j, k, det = 1; ll coe;
  3. static int *m[N];
  4. for (i = 0; i < n; ++i) m[i] = mat[i];
  5. for (i = 0; i < n; ++i) {
  6. for (j = i; j < n && !m[j][i]; ++j);
  7. if (j == n) return 0;
  8. if (i != j) det = mod - det, std::swap(m[i], m[j]);
  9. det = (ll)det * m[i][i] % mod;
  10. coe = PowerMod(m[i][i], mod - 2);
  11. for (j = 0; j < n; ++j) m[i][j] = m[i][j] * coe % mod;
  12. for (k = i + 1; k < n; ++k)
  13. for (coe = mod - m[k][i], j = i; j < n; ++j) m[k][j] = (m[k][j] + coe * m[i][j]) % mod;
  14. }
  15. return det;
  16. }

Nim 积 (32/64 bit) [#ed11]:

  1. namespace nimbers {
  2. constexpr u32 n2f[16] = {0x0001u, 0x8ff5u, 0x6cbfu, 0xa5beu, 0x761au, 0x8238u, 0x4f08u, 0x95acu, 0xf340u, 0x1336u, 0x7d5eu, 0x86e7u, 0x3a47u, 0xe796u, 0xb7c3u, 0x0008u},
  3. f2n[16] = {0x0001u, 0x2827u, 0x392bu, 0x8000u, 0x20fdu, 0x4d1du, 0xde4au, 0x0a17u, 0x3464u, 0xe3a9u, 0x6d8du, 0x34bcu, 0xa921u, 0xa173u, 0x0ebcu, 0x0e69u};
  4. inline u32 nimber2field(u32 x) {u32 y = 0; for (; x; x &= x - 1) y ^= n2f[ctz(x)]; return y;}
  5. inline u32 field2nimber(u32 x) {u32 y = 0; for (; x; x &= x - 1) y ^= f2n[ctz(x)]; return y;}
  6. inline u32 __builtin_double(u32 x) {return x << 1 ^ (x < 0x8000u ? 0 : 0x1681fu);}
  7. u16 ln[65536], exp[131075], *Hexp = exp + 3, *H2exp = exp + 6;
  8. inline void init() {
  9. int i;
  10. for (*exp = i = 1; i < 65535; ++i) exp[i] = __builtin_double(exp[i - 1]);
  11. for (i = 1; i < 65535; ++i) exp[i] = field2nimber(exp[i]), ln[exp[i]] = i;
  12. memcpy(exp + 65535, exp, 131070);
  13. memcpy(exp + 131070, exp, 10);
  14. }
  15. inline u16 product(u16 A, u16 B) {return A && B ? exp[ln[A] + ln[B]] : 0;}
  16. inline u16 H(u16 A) {return A ? Hexp[ln[A]] : 0;}
  17. inline u16 H2(u16 A) {return A ? H2exp[ln[A]] : 0;}
  18. inline u16 Hproduct(u16 A, u16 B) {return A && B ? Hexp[ln[A] + ln[B]] : 0;}
  19. inline u32 product(u32 A, u32 B) {
  20. u16 a = A & 65535, b = B & 65535, c = A >> 16, d = B >> 16, e = product(a, b);
  21. return u32(product(u16(a ^ c), u16(b ^ d)) ^ e) << 16 | (Hproduct(c, d) ^ e);
  22. }
  23. inline u32 H(u32 A) {
  24. u16 a = A & 65535, b = A >> 16;
  25. return H(u16(a ^ b)) << 16 | H2(b);
  26. }
  27. inline u64 product(u64 A, u64 B) {
  28. u32 a = A & UINT_MAX, b = B & UINT_MAX, c = A >> 32, d = B >> 32, e = product(a, b);
  29. return u64(product(a ^ c, b ^ d) ^ e) << 32 | (H(product(c, d)) ^ e);
  30. }
  31. }

01 背包问题 [#ed12]:

  1. // 01 背包
  2. // 有 N 件物品和一个容量为 V 的背包
  3. // 第 i 件物品费用是 c[i],价值是 w[i]
  4. // 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
  5. // 无优化
  6. for (int i = 1; i <= N; i++)
  7. {
  8. for (int j = 1; j <= V; j++)
  9. {
  10. if (j < c[i]) dp[i][j] = dp[i - 1][j];
  11. else dp[i][j] = std::max(dp[i - 1][j], dp[i - 1][j - c[i]] + w[i]);
  12. }
  13. }
  14. // 空间优化
  15. for (int i = 1; i <= N; i++)
  16. {
  17. for (int j = V; j >= c[i]; j--)
  18. {
  19. dp[j] = std::max(dp[j], dp[j - c[i]] + w[i]);
  20. }
  21. }

多重背包问题 [#ed13]:

  1. // 多重背包问题
  2. // 有 N 件物品和一个容量为 V 的背包,每种物品都有无限件可用
  3. // 第 i 件物品费用是 c[i],价值是 w[i]
  4. // 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
  5. // 无优化
  6. for (int i = 1; i <= N; i++)
  7. {
  8. for (int j = 1; j <= V; j++)
  9. {
  10. dp[i][j] = dp[i - 1][j];
  11. if (j >= c[i]) dp[i][j] = std::max(dp[i - 1][j], dp[i][j - c[i]] + w[i]);
  12. }
  13. }
  14. // 空间优化
  15. for (int i = 1; i <= N; i++)
  16. {
  17. for (int j = c[i]; j <= V; j++)
  18. {
  19. dp[j] = std::max(dp[j], dp[j - c[i]] + w[i]);
  20. }
  21. }

整数二分 [#ed14]:

  1. bool check(int x) {/* ... */} // 检查x是否满足某种性质
  2. // 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
  3. int bsearch(int l, int r)
  4. {
  5. while (l < r)
  6. {
  7. int mid = l + r << 1;
  8. if (check(mid)) r = mid; // check()判断mid是否满足性质
  9. else l = mid + 1;
  10. }
  11. return l;
  12. }
  13. // 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
  14. int bsearch(int l, int r)
  15. {
  16. while (l < r)
  17. {
  18. int mid = l + r + 1 << 1;
  19. if (check(mid)) l = mid;
  20. else r = mid - 1;
  21. }
  22. return l;
  23. }

高精度加法 [#ed15]:

  1. std::vector <int> add(std::vector <int> &A, std::vector <int> &B)
  2. {
  3. std::vector <int> C;
  4. int t = 0;
  5. for (int i = 0; i < A.size() || i < B.size(); i++)
  6. {
  7. if (i < A.size()) t += A[i];
  8. if (i < B.size()) t += B[i];
  9. C.push_back(t % 10);
  10. t /= 10;
  11. }
  12. if (t) C.push_back(1);
  13. return C;
  14. }

二维向量/点、计算几何基础 [#cg01]:

  1. const double eps = 1e-8;
  2. #define lt(x, y) ((x) < (y) - eps)
  3. #define gt(x, y) ((x) > (y) + eps)
  4. #define le(x, y) ((x) <= (y) + eps)
  5. #define ge(x, y) ((x) >= (y) - eps)
  6. #define eq(x, y) (le(x, y) && ge(x, y))
  7. #define dot(x, y, z) (((y) - (x)) * ((z) - (x)))
  8. #define cross(x, y, z) (((y) - (x)) ^ ((z) - (x)))
  9. struct vec2 {
  10. double x, y;
  11. vec2 (double x0 = 0.0, double y0 = 0.0) : x(x0), y(y0) {}
  12. vec2 * read() {scanf("%lf%lf", &x, &y); return this;}
  13. inline vec2 operator - () const {return vec2(-x, -y);}
  14. inline vec2 operator + (const vec2 &B) const {return vec2(x + B.x, y + B.y);}
  15. inline vec2 operator - (const vec2 &B) const {return vec2(x - B.x, y - B.y);}
  16. inline vec2 operator * (double k) const {return vec2(x * k, y * k);}
  17. inline vec2 operator / (double k) const {return *this * (1.0 / k);}
  18. inline double operator * (const vec2 &B) const {return x * B.x + y * B.y;}
  19. inline double operator ^ (const vec2 &B) const {return x * B.y - y * B.x;}
  20. inline double norm2() const {return x * x + y * y;}
  21. inline double norm() const {return sqrt(x * x + y * y);}
  22. inline bool operator < (const vec2 &B) const {return lt(x, B.x) || le(x, B.x) && lt(y, B.y);}
  23. inline bool operator == (const vec2 &B) const {return eq(x, B.x) && eq(y, B.y);}
  24. inline bool operator << (const vec2 &B) const {return lt(y, 0) ^ lt(B.y, 0) ? lt(B.y, 0) : gt(*this ^ B, 0) || ge(*this ^ B, 0) && ge(x, 0) && lt(B.x, 0);}
  25. inline vec2 trans(double a11, double a12, double a21, double a22) const {return vec2(x * a11 + y * a12, x * a21 + y * a22);}
  26. };
  27. /*
  28. operator * : Dot product
  29. operator ^ : Cross product
  30. norm2() : |v|^2 = v.v
  31. norm() : |v| = sqrt(v.v)
  32. operator < : Two-key compare
  33. operator << : Polar angle compare
  34. trans : Transition with a 2x2 matrix
  35. */

直线及其函数 [#cg02]:

  1. struct line {
  2. double A, B, C; // Ax + By + C = 0, > 0 if it represents halfplane.
  3. line (double A0 = 0.0, double B0 = 0.0, double C0 = 0.0) : A(A0), B(B0), C(C0) {}
  4. line (const vec2 &u, const vec2 &v) : A(u.y - v.y), B(v.x - u.x), C(u ^ v) {} // left > 0
  5. inline vec2 normVec() const {return vec2(A, B);}
  6. inline double norm2() const {return A * A + B * B;}
  7. inline double operator () (const vec2 &P) const {return A * P.x + B * P.y + C;}
  8. };
  9. inline vec2 intersection(const line u, const line v) {return vec2(u.B * v.C - u.C * v.B, u.C * v.A - u.A * v.C) / (u.A * v.B - u.B * v.A);}
  10. inline bool parallel(const line u, const line v) {double p = u.normVec() ^ v.normVec(); return eq(p, 0);}
  11. inline bool perpendicular(const line u, const line v) {double p = u.normVec() * v.normVec(); return eq(p, 0);}
  12. inline bool sameDir(const line u, const line v) {return parallel(u, v) && gt(u.normVec() * v.normVec(), 0);}
  13. inline line bisector(const vec2 u, const vec2 v) {return line(v.x - u.x, v.y - u.y, 0.5 * (u.norm2() - v.norm2()));}
  14. inline double dis2(const vec2 P, const line l) {return l(P) * l(P) / l.norm2();}
  15. inline vec2 projection(const vec2 P, const line l) {return P - l.normVec() * (l(P) / l.norm2());}
  16. inline vec2 symmetry(const vec2 P, const line l) {return P - l.normVec() * (2 * l(P) / l.norm2());}

多边形操作 [#cg03]:

  1. // Relation of 3 points. (2 inside, 1 outside, 0 not collinear)
  2. inline int collinear(const vec2 u, const vec2 v, const vec2 P) {double p = cross(P, u, v); return eq(p, 0) ? 1 + le(dot(P, u, v), 0) : 0;}
  3. // Perimeter of a polygon
  4. double perimeter(int n, vec2 *poly) {
  5. double ret = (poly[n - 1] - *poly).norm();
  6. for (int i = 1; i < n; ++i) ret += (poly[i - 1] - poly[i]).norm();
  7. return ret;
  8. }
  9. // Directed area of a polygon (positive if CCW)
  10. double area(int n, vec2 *poly) {
  11. double ret = poly[n - 1] ^ *poly;
  12. for (int i = 1; i < n; ++i) ret += poly[i - 1] ^ poly[i];
  13. return ret * 0.5;
  14. }
  15. // Point in polygon (2 on boundary, 1 inside, 0 outside)
  16. int contain(int n, vec2 *poly, const vec2 P) {
  17. int in = 0; vec2 *r = poly + (n - 1), *u, *v;
  18. for (int i = 0; i < n; r = poly, ++poly, ++i) {
  19. if (collinear(*r, *poly, P) == 2) return 2;
  20. gt(r->y, poly->y) ? (u = poly, v = r) : (u = r, v = poly);
  21. if (ge(P.y, v->y) || lt(P.y, u->y)) continue;
  22. in ^= gt(cross(P, *u, *v), 0);
  23. }
  24. return in;
  25. }

平面凸包 (Graham Scan) [#cg04]:

  1. int graham(int n, vec2 *p, vec2 *dest) {
  2. int i; vec2 *ret = dest;
  3. std::iter_swap(p, std::min_element(p, p + n));
  4. std::sort(p + 1, p + n, [p] (const vec2 A, const vec2 B) {double r = cross(*p, A, B); return gt(r, 0) || (ge(r, 0) && lt((A - *p).norm2(), (B - *p).norm2()));});
  5. for (i = 0; i < 2 && i < n; ++i) *ret++ = p[i];
  6. for (; i < n; *ret++ = p[i++])
  7. for (; ret != dest + 1 && ge(cross(ret[-2], p[i], ret[-1]), 0); --ret);
  8. return *ret = *p, ret - dest;
  9. }

旋转卡壳求凸集直径 [#cg05]:

  1. double convDiameter(int n, vec2 *poly) {
  2. int l = std::min_element(poly, poly + n) - poly, r = std::max_element(poly, poly + n) - poly, i = l, j = r;
  3. double diam = (poly[l] - poly[r]).norm2();
  4. do {
  5. (ge(poly[(i + 1) % n] - poly[i] ^ poly[(j + 1) % n] - poly[j], 0) ? ++j : ++i) %= n;
  6. up(diam, (poly[i] - poly[j]).norm2());
  7. } while (i != l || j != r);
  8. return diam;
  9. }

三角形外心 & 最小圆覆盖 [#cg06]:

  1. inline vec2 circumCenter(const vec2 A, const vec2 B, const vec2 C) {
  2. vec2 a = B - A, b = C - A, AO;
  3. double det = 0.5 / (a ^ b), na = a.norm2(), nb = b.norm2();
  4. AO = vec2((na * b.y - nb * a.y) * det, (nb * a.x - na * b.x) * det);
  5. return A + AO;
  6. }
  7. double minCircleCover(int n, vec2 *p, vec2 *ret = NULL) {
  8. int i, j, k; double r2 = 0.0;
  9. std::random_shuffle(p + 1, p + (n + 1));
  10. vec2 C = p[1];
  11. for (i = 2; i <= n; ++i)
  12. if (gt((p[i] - C).norm2(), r2))
  13. for (C = p[i], r2 = 0, j = 1; j < i; ++j)
  14. if (gt((p[j] - C).norm2(), r2))
  15. for (C = (p[i] + p[j]) * 0.5, r2 = (p[j] - C).norm2(), k = 1; k < j; ++k)
  16. if (gt((p[k] - C).norm2(), r2))
  17. C = circumCenter(p[i], p[j], p[k]), r2 = (p[k] - C).norm2();
  18. return ret ? *ret = C : 0, r2;
  19. }

半平面交 (平行处理版) [#cg07]:

  1. inline bool HPIcmp(const line u, const line v) {return sameDir(u, v) ? gt((fabs(u.A) + fabs(u.B)) * v.C, (fabs(v.A) + fabs(v.B)) * u.C) : u.normVec() << v.normVec();}
  2. inline bool geStraight(const vec2 A, const vec2 B) {return lt(A ^ B, 0) || le(A ^ B, 0) && lt(A * B, 0);}
  3. inline bool para_nega_test(const line u, const line v) {
  4. return parallel(u, v) && lt(u.normVec() * v.normVec(), 0) && (fabs(u.A) + fabs(u.B)) * v.C + (fabs(v.A) + fabs(v.B)) * u.C < -7e-14;
  5. }
  6. int HPI(int n, line *l, vec2 *poly, vec2 *&ret) { // -1 : Unbounded, -2 : Infeasible
  7. int h = 0, t = -1, i, j, que[n + 5];
  8. std::sort(l, l + n, HPIcmp);
  9. n = std::unique(l, l + n, sameDir) - l;
  10. for (j = i = 0; i < n && j < n; ++i) {
  11. for (up(j, i + 1); j < n && !geStraight(l[i].normVec(), l[j].normVec()); ++j);
  12. if (para_nega_test(l[i], l[j])) return -2;
  13. }
  14. if (n <= 2 || geStraight(l[n - 1].normVec(), l->normVec())) return -1;
  15. for (i = 0; i < n; ++i) {
  16. if (geStraight(l[que[t]].normVec(), l[i].normVec())) return -1;
  17. for (; h < t && le(l[i](poly[t - 1]), 0); --t);
  18. for (; h < t && le(l[i](poly[h]), 0); ++h);
  19. que[++t] = i; h < t ? poly[t - 1] = intersection(l[ que[t - 1] ], l[ que[t] ]) : 0;
  20. }
  21. for (; h < t && le(l[ que[h] ](poly[t - 1]), 0); --t);
  22. return h == t ? -2 : (poly[t] = intersection(l[ que[t] ], l[ que[h] ]), ret = poly + h, t - h + 1);
  23. }

平面上的圆几何 [#cg08]:

  1. const double pi = M_PI, pi2 = pi * 2., pi_2 = M_PI_2;
  2. inline double angle(const vec2 u, const vec2 v) {return atan2(u ^ v, u * v);}
  3. // intersection of circle and line
  4. int intersection(double r2, const vec2 O, const line l, vec2 *ret) {
  5. double d2 = dis2(O, l); vec2 j = l.normVec();
  6. if (gt(d2, r2)) return ret[0] = ret[1] = vec2(INFINITY, INFINITY), 0;
  7. if (ge(d2, r2)) return ret[0] = ret[1] = projection(O, l), 1;
  8. if (le(d2, 0)) {
  9. j = j * sqrt(r2 / j.norm2());
  10. ret[0] = O + j.trans(0, -1, 1, 0);
  11. ret[1] = O + j.trans(0, 1, -1, 0);
  12. } else {
  13. double T = copysign(sqrt((r2 - d2) / d2), l(O)); j = j * (-l(O) / j.norm2());
  14. ret[0] = O + j.trans(1, T, -T, 1);
  15. ret[1] = O + j.trans(1, -T, T, 1);
  16. }
  17. return 2;
  18. }
  19. // area of intersection(x^2 + y^2 = r^2, triangle OBC)
  20. double interArea(double r2, const vec2 B, const vec2 C) {
  21. if (eq(B ^ C, 0)) return 0;
  22. vec2 is[2];
  23. if (!intersection(r2, vec2(), line(B, C), is)) return 0.5 * r2 * angle(B, C);
  24. bool b = gt(B.norm2(), r2), c = gt(C.norm2(), r2);
  25. if (b && c) return 0.5 * (lt(dot(*is, B, C), 0) ? r2 * (angle(B, *is) + angle(is[1], C)) + (is[0] ^ is[1]) : r2 * angle(B, C));
  26. else if (b) return 0.5 * (r2 * angle(B, *is) + (*is ^ C));
  27. else if (c) return 0.5 * ((B ^ is[1]) + r2 * angle(is[1], C));
  28. else return 0.5 * (B ^ C);
  29. }
  30. // tangents to circle((0, 0), r) through P
  31. int tangent(double r, const vec2 P, line *ret) {
  32. double Q = P.norm2() - r * r;
  33. if (lt(Q, 0)) return ret[0] = ret[1] = line(INFINITY, INFINITY, INFINITY), 0;
  34. if (le(Q, 0)) return ret[0] = ret[1] = line(P.x, P.y, -P.norm2()), 1;
  35. Q = sqrt(Q) / r;
  36. ret[0] = line(P.x + Q * P.y, P.y - Q * P.x, -P.norm2());
  37. ret[1] = line(P.x - Q * P.y, P.y + Q * P.x, -P.norm2());
  38. return 2;
  39. }
  40. // tangets to circle(O, r) through P
  41. int tangent(double r, const vec2 O, const vec2 P, line *ret) {
  42. int R = tangent(r, P - O, ret);
  43. if (R)
  44. ret[0].C -= ret[0].A * O.x + ret[0].B * O.y,
  45. ret[1].C -= ret[1].A * O.x + ret[1].B * O.y;
  46. return R;
  47. }

三维计算几何基础 [#cg09]:

  1. #define triple(x, y, z) ((x) * ((y) ^ (z)))
  2. struct vec3 {
  3. double x, y, z;
  4. vec3 (double x0 = 0, double y0 = 0, double z0 = 0) : x(x0), y(y0), z(z0) {}
  5. vec3 * read() {scanf("%lf%lf%lf", &x, &y, &z); return this;}
  6. inline vec3 operator - () const {return vec3(-x, -y, -z);}
  7. inline vec3 operator + (const vec3 &B) const {return vec3(x + B.x, y + B.y, z + B.z);}
  8. inline vec3 operator - (const vec3 &B) const {return vec3(x - B.x, y - B.y, z - B.z);}
  9. inline vec3 operator * (double k) const {return vec3(x * k, y * k);}
  10. inline vec3 operator / (double k) const {return *this * (1.0 / k);}
  11. inline double operator * (const vec3 &B) const {return x * B.x + y * B.y + z * B.z;}
  12. inline vec3 operator ^ (const vec3 &B) const {return vec3(y * B.z - z * B.y, z * B.x - x * B.z, x * B.y - y * B.x);}
  13. inline double norm2() const {return x * x + y * y + z * z;}
  14. inline double norm() const {return sqrt(x * x + y * y + z * z);}
  15. inline bool operator < (const vec3 &B) const {return lt(x, B.x) || le(x, B.x) && (lt(y, B.y) || le(y, B.y) && lt(z, B.z));}
  16. inline bool operator == (const vec3 &B) const {return eq(x, B.x) && eq(y, B.y) && eq(z, B.z);}
  17. };
  18. // Positive if Right-hand rule
  19. inline double volume(const vec3 A, const vec3 B, const vec3 C, const vec3 D) {return triple(B - A, C - A, D - A);}
  20. struct line3 {
  21. vec3 P, t;
  22. line3 (vec3 _P = vec3(), vec3 _t = vec3()) : P(_P), t(_t) {}
  23. };
  24. inline double dis2(const vec3 P, const line3 l) {return ((P - l.P) ^ l.t).norm2() / l.t.norm2();}
  25. struct plane {
  26. double A, B, C, D; // Ax + By + Cz + D = 0
  27. plane (double A0 = 0.0, double B0 = 0.0, double C0 = 0.0, double D0 = 0.0) : A(A0), B(B0), C(C0), D(D0) {}
  28. plane (const vec3 &u, const vec3 &v, const vec3 &w) {vec3 t = (v - u) ^ (w - u); A = t.x, B = t.y, C = t.z, D = -triple(u, v, w);} // > 0 if it follows Right-hand rule
  29. inline vec3 normVec() const {return vec3(A, B, C);}
  30. inline double norm2() const {return A * A + B * B + C * C;}
  31. inline double operator () (const vec3 &P) const {return A * P.x + B * P.y + C * P.z + D;}
  32. };
  33. inline double dis2(const vec3 P, const plane F) {return F(P) * F(P) / F.norm2();}

三维凸包 (卷包裹法) [#cg10]:

  1. namespace CH3D {
  2. typedef std::pair <int, int> pr;
  3. typedef std::set <pr> set;
  4. struct triangle {vec3 A, B, C;} tr[N];
  5. vec3 p[N], q[N], r[N];
  6. set E;
  7. int n, cnt;
  8. inline vec3 randvec3() {return vec3((double)rand() / RAND_MAX, (double)rand() / RAND_MAX, (double)rand() / RAND_MAX);}
  9. void wrap(int u, int v) {
  10. if (E.find({u, v}) == E.end()) {
  11. int i, w = -1;
  12. for (i = 0; i < n; ++i)
  13. if (i != u && i != v && (!~w || ge(volume(q[w], q[u], q[v], q[i]), 0))) w = i;
  14. if (~w) {
  15. tr[cnt++] = (triangle){p[u], p[v], p[w]};
  16. E.emplace(u, v); E.emplace(v, w); E.emplace(w, u);
  17. wrap(w, v); wrap(u, w);
  18. }
  19. }
  20. }
  21. void main(int _n, vec3 *_p) {
  22. int i;
  23. n = _n; cnt = 0; E.clear();
  24. memcpy(p, _p, n * sizeof(vec3));
  25. std::iter_swap(p, std::min_element(p, p + n));
  26. for (i = 0; i < n; ++i) q[i] = p[i] + randvec3() * 1e-6;
  27. for (i = 2; i < n; ++i)
  28. if (ge(cross(q[0], q[i], q[1]).z, 0)) std::swap(p[1], p[i]), std::swap(q[1], q[i]);
  29. wrap(0, 1);
  30. }
  31. }

自适应 Simpson 积分 [#cg11]:

  1. double Simpson(double L, double M, double R, double fL, double fM, double fR, double eps) {
  2. double LM = (L + M) * 0.5, fLM = f(LM), MR = (M + R) * 0.5, fMR = f(MR);
  3. double A = (fL + fM * 4.0 + fR) * (R - L) * sixth,
  4. AL = (fL + fLM * 4.0 + fM) * (M - L) * sixth,
  5. AR = (fM + fMR * 4.0 + fR) * (R - M) * sixth;
  6. if (fabs(AL + AR - A) < eps) return (2.0 * (AL + AR) + A) * third;
  7. return Simpson(L, LM, M, fL, fLM, fM, eps * 0.6) + Simpson(M, MR, R, fM, fMR, fR, eps * 0.6);
  8. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注