From a541c86d9be0dd0d7acbd0e5324103a9e4368d8f Mon Sep 17 00:00:00 2001
From: qdd <yyluo9904@gmail.com>
Date: Thu, 24 Nov 2022 13:59:59 -0800
Subject: [PATCH] translate

---
 0-IO.md         |  112 +++++
 1-Structure.md  |  917 ++++++++++++++++++++++--------------
 2-Graph.md      |  677 +++++++++++++++++++++++++++
 3-String.md     |  426 +++++++++++++++++
 4-Math.md       | 1015 ++++++++++++++++++++++++++++++++++++++++
 5-Geometry.md   |  315 +++++++++++++
 6-Other.md      | 1182 +++++++++++++++++++++++++++++++++++++++++++++++
 9-Unverified.md |  766 ++++++++++++++++++++++++++++++
 LICENSE         |   21 +
 README.md       |    1 +
 10 files changed, 5092 insertions(+), 340 deletions(-)
 create mode 100644 0-IO.md
 create mode 100644 2-Graph.md
 create mode 100644 3-String.md
 create mode 100644 4-Math.md
 create mode 100644 5-Geometry.md
 create mode 100644 6-Other.md
 create mode 100644 9-Unverified.md
 create mode 100644 LICENSE
 create mode 100644 README.md

diff --git a/0-IO.md b/0-IO.md
new file mode 100644
index 0000000..0f0c6d8
--- /dev/null
+++ b/0-IO.md
@@ -0,0 +1,112 @@
+## Input & Output
+
+### format strings
+
+```cpp
+long double %Lf
+unsigned int %u
+unsigned long long %llu
+
+cout << fixed << setprecision(15);
+```
+
+### file, fast std::cin
+
+```cpp
+freopen("in.txt", "r", stdin);
+
+ios::sync_with_stdio(false);
+cin.tie(0);
+```
+
+### timing
+
+```cpp
+(double)clock() / CLOCKS_PER_SEC
+```
+
+### read the whole line
+
+```cpp
+scanf("%[^\n]", s)  // need to be tested before use
+getline(cin, s)
+```
+
+### Read to EOF
+
+```cpp
+while (cin) {}
+while (~scanf) {}
+```
+
+### int128
+
+```cpp
+// need to be tested before use
+inline __int128 get128() {
+    __int128 x = 0, sgn = 1;
+    char c = getchar();
+    for (; c < '0' || c > '9'; c = getchar()) if (c == '-') sgn = -1;
+    for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
+    return sgn * x;
+}
+
+inline void print128(__int128 x) {
+    if (x < 0) {
+        putchar('-');
+        x = -x;
+    }
+    if (x >= 10) print128(x / 10);
+    putchar(x % 10 + '0');
+}
+```
+
+### ultimate fast input
+
+```cpp
+class Scanner {
+#ifdef qdd
+    static constexpr int BUF_SIZE = 1;
+#else
+    static constexpr int BUF_SIZE = 1048576; // 1MB
+#endif
+
+    char buf[BUF_SIZE], *p1 = buf, *p2 = buf;
+
+    char nc() {
+        if (p1 == p2) {
+            p1 = buf; p2 = buf + fread(buf, 1, BUF_SIZE, stdin);
+            // assert(p1 != p2);
+        }
+        return *p1++;
+    }
+
+public:
+    string next() {
+        string s;
+        char c = nc();
+        while (c <= 32) c = nc();
+        for (; c > 32; c = nc()) s += c;
+        return s;
+    }
+
+    int nextInt() {
+        int x = 0, sgn = 1;
+        char c = nc();
+        for (; c < '0' || c > '9'; c = nc()) if (c == '-') sgn = -1;
+        for (; c >= '0' && c <= '9'; c = nc()) x = x * 10 + (c - '0');
+        return sgn * x;
+    }
+
+    double nextDouble() {
+        double x = 0, base = 0.1;
+        int sgn = 1;
+        char c = nc();
+        for (; c < '0' || c > '9'; c = nc()) if (c == '-') sgn = -1;
+        for (; c >= '0' && c <= '9'; c = nc()) x = x * 10 + (c - '0');
+        for (; c < '0' || c > '9'; c = nc()) if (c != '.') return sgn * x;
+        for (; c >= '0' && c <= '9'; c = nc()) x += base * (c - '0'), base *= 0.1;
+        return sgn * x;
+    }
+} in;
+```
diff --git a/1-Structure.md b/1-Structure.md
index c238654..6b46d9c 100644
--- a/1-Structure.md
+++ b/1-Structure.md
@@ -1,30 +1,49 @@
-## 4.1 数据结构
+## Data Structures
 
-### 并查集
+### disjoint set union
 
 ```cpp
-int pa[MAXN];
+struct dsu {
+    vector<int> p, sz;
+    dsu(int n) : p(n), sz(n, 1) { iota(p.begin(), p.end(), 0); }
+    int find(int x) { return (x == p[x]) ? x : p[x] = find(p[x]); }
+    bool merge(int x, int y) {
+        x = find(x), y = find(y);
+        if (x == y) return 0;
+        p[x] = y;
+        sz[y] += sz[x];
+        sz[x] = 0;
+        return 1;
+    }
+};
+```
 
-int find(int x) {
-    if (x == pa[x]) return x;
-    return pa[x] = find(pa[x]);
-}
++ dynamic dsu (for large range values)
+
+```cpp
+// pa is the set size if negative
+unordered_map<int, int> pa;
+
+void _set(int x) { if (!pa.count(x)) pa[x] = -1; }
+int find(int x) { return (pa[x] < 0) ? x : pa[x] = find(pa[x]); }
 
 void merge(int a, int b) {
-    int fa = find(a);
-    int fb = find(b);
-    if (fa != fb) pa[fa] = fb;
+    int x = find(a), y = find(b);
+    if (x == y) return;
+    if (pa[x] > pa[y]) swap(x, y);
+    pa[x] += pa[y];
+    pa[y] = x;
 }
 ```
 
-### RMQ
+### sparse table
+
++ 1D
 
 ```cpp
-// 下标从0开始
+// 0-indexed
 struct RMQ {
-    int st[MAXN][22]; // 22 = ((int)log2(MAXN) + 1)
-
-    int xlog(int x) { return 31 - __builtin_clz(x); }
+    int st[N][22]; // 22 = ((int)log2(N) + 1)
 
     void init(int *a, int n) {
         for (int i = 0; i < n; i++) {
@@ -38,440 +57,658 @@ struct RMQ {
     }
 
     int query(int l, int r) {
-        int x = xlog(r - l + 1);
+        int x = __lg(r - l + 1);
         return max(st[l][x], st[r - (1 << x) + 1][x]);
     }
 };
 ```
 
-### 分块
++ 2D
 
 ```cpp
-// 代码长度没有优势
-// 下标从1开始
-// 区间加,区间和
-struct Node {
-    int l, r;
-    long long val, lazy;
-};
+struct RMQ {
+    int st[11][11][N][N]; // 11 = ((int)log2(N) + 1)
 
-struct Block {
-    int size, b_size; // b_size块 每块大小b_size
-    long long *a;
-    Node *b;
-    int *pos;
-
-    Block(int sz) {
-        b_size = ceil(sqrt(sz + 0.5));
-        size = b_size * b_size;
-        a = new long long[size + 1];
-        b = new Node[b_size + 1];
-        pos = new int[size + 1];
-        for (int i = 1; i <= b_size; i++) {
-            b[i].l = (i - 1) * b_size + 1;
-            b[i].r = i * b_size;
-            b[i].val = b[i].lazy = 0;
+    void init(int n, int m) {
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < m; j++) {
+                st[0][0][i][j] = a[i][j];
+            }
         }
-        for (int i = 1; i <= size; i++) {
-            a[i] = 0;
-            pos[i] = (i - 1) / b_size + 1;
+        for (int i = 0; (1 << i) <= n; i++) {
+            for (int j = 0; (1 << j) <= m; j++) {
+                if (i == 0 && j == 0) continue;
+                for (int r = 0; r + (1 << i) - 1 < n; r++) {
+                    for (int c = 0; c + (1 << j) - 1 < m; c++) {
+                        if (i == 0) {
+                            st[i][j][r][c] = max(st[i][j - 1][r][c], st[i][j - 1][r][c + (1 << (j - 1))]);
+                        } else {
+                            st[i][j][r][c] = max(st[i - 1][j][r][c], st[i - 1][j][r + (1 << (i - 1))][c]);
+                        }
+                    }
+                }
+            }
         }
     }
 
-    ~Block() {
-        delete [] a;
-        delete [] b;
-        delete [] pos;
+    int query(int r1, int c1, int r2, int c2) {
+        int x = __lg(r2 - r1 + 1);
+        int y = __lg(c2 - c1 + 1);
+        int m1 = st[x][y][r1][c1];
+        int m2 = st[x][y][r1][c2 - (1 << y) + 1];
+        int m3 = st[x][y][r2 - (1 << x) + 1][c1];
+        int m4 = st[x][y][r2 - (1 << x) + 1][c2 - (1 << y) + 1];
+        return max({m1, m2, m3, m4});
     }
+};
+```
 
-    void pushdown(int p) {
-        if (!b[p].lazy) return;
-        for (int i = b[p].l; i <= b[p].r; i++) {
-            a[i] += b[p].lazy;
-        }
-        b[p].lazy = 0;
++ sliding window RMQ
+
+```cpp
+// k is the window size
+deque<int> q;
+for (int i = 0, j = 0; i + k <= n; i++) {
+    while (j < i + k) {
+        while (!q.empty() && a[q.back()] < a[j]) q.pop_back(); // take the '>' sign for range minimum
+        q.push_back(j++);
     }
+    while (q.front() < i) q.pop_front();
+    rmq.push_back(a[q.front()]);
+}
+```
 
-    void update(int l, int r, int val) {
-        for (int i = pos[l]; i <= pos[r]; i++) {
-            if (b[i].l < l || b[i].r > r) {
-                pushdown(i);
-                for (int j = max(l, b[i].l); j <= min(r, b[i].r); j++) {
-                    a[j] += val;
-                    b[i].val += val;
-                }
-            } else {
-                b[i].val += (b[i].r - b[i].l + 1) * val;
-                b[i].lazy += val;
+### binary indexed tree (aka Fenwick tree)
+
++ point modify, range sum
+
+```cpp
+// support find kth element
+// 1-indexed
+struct fenwick {
+    int n;
+    vector<ll> t;
+    fenwick(int n) : n(n), t(n + 1) {}
+    void add(int p, ll x) {
+        // assert(p > 0);
+        for (; p <= n; p += p & -p) t[p] += x;
+    }
+    ll get(int p) {
+        ll a = 0;
+        for (; p > 0; p -= p & -p) a += t[p];
+        return a;
+    }
+    void update(int p, ll x) { add(p, x - query(p, p)); }
+    ll query(int l, int r) { return get(r) - get(l - 1); }
+
+    int kth(ll k) {
+        int p = 0;
+        for (int i = __lg(n); i >= 0; i--) {
+            int p_ = p + (1 << i);
+            if (p_ <= n && t[p_] < k) {
+                k -= t[p_];
+                p = p_;
             }
         }
+        return p + 1;
     }
+};
+```
 
-    long long query(int l, int r) {
-        long long ret = 0;
-        for (int i = pos[l]; i <= pos[r]; i++) {
-            if (b[i].l < l || b[i].r > r) {
-                pushdown(i);
-                for (int j = max(l, b[i].l); j <= min(r, b[i].r); j++) {
-                    ret += a[j];
-                }
-            } else {
-                ret += b[i].val;
-            }
-        }
-        return ret;
++ 0-indexed
+
+```cpp
+struct fenwick {
+    int n;
+    vector<ll> t;
+    fenwick(int n) : n(n), t(n) {}
+    void add(int p, ll x) {
+        // assert(p >= 0);
+        for (; p < n; p |= p + 1) t[p] += x;
+    }
+    ll get(int p) {
+        ll a = 0;
+        for (; p >= 0; p = (p & (p + 1)) - 1) a += t[p];
+        return a;
     }
 };
 ```
 
-### 树状数组
++ range add, point query
 
 ```cpp
-// 下标从1开始
-// 修改:单点
-// 查询:区间和
-struct Tbit {
-    int size;
-    long long t[MAXN];
+void range_add(int l, int r, ll x) {
+    add(l, x);
+    add(r + 1, -x);
+}
+```
 
-    int lowbit(int x) { return x & (-x); }
++ range add, range sum
 
-    void init(int sz) {
-        size = sz;
-        memset(t, 0, (sz + 1) * sizeof(long long));
-    }
+```cpp
+fenwick t1, t2;
 
-    void add(int pos, long long val) {
-        if (pos <= 0) return;
-        while (pos <= size) {
-            t[pos] += val;
-            pos += lowbit(pos);
-        }
+void range_add(int l, int r, ll x) {
+    t1.add(l, x);
+    t2.add(l, l * x);
+    t1.add(r + 1, -x);
+    t2.add(r + 1, (r + 1) * -x);
+}
+
+ll range_sum(int l, int r) {
+    return (r + 1) * t1.get(r) - t2.get(r) - l * t1.get(l - 1) + t2.get(l - 1);
+}
+```
+
++ 2D fenwick
+
+```cpp
+struct fenwick {
+    ll t[N][N];
+
+    int lowbit(int x) { return x & (-x); }
+
+    void add(int x, int y, int d) {
+        for (int i = x; i <= n; i += lowbit(i))
+            for (int j = y; j <= m; j += lowbit(j)) t[i][j] += d;
     }
 
-    long long get(int pos) {
-        long long sum = 0;
-        while (pos > 0) {
-            sum += t[pos];
-            pos -= lowbit(pos);
-        }
+    ll get(int x, int y) {
+        ll sum = 0;
+        for (int i = x; i > 0; i -= lowbit(i))
+            for (int j = y; j > 0; j -= lowbit(j)) sum += t[i][j];
         return sum;
     }
 
-    void update(int pos, long long val) { add(pos, val - query(pos, pos)); }
-    long long query(int l, int r) { return get(r) - get(l - 1); }
+    ll query(int x, int y, int xx, int yy) {
+        return get(xx, yy) - get(x - 1, yy) - get(xx, y - 1) + get(x - 1, y - 1);
+    }
 };
+```
+
++ 2D range add, range sum
+
+```cpp
+fenwick t0, t1, t2, t3;
+
+void add4(int x, int y, ll d) {
+    t0.add(x, y, d);
+    t1.add(x, y, d * x);
+    t2.add(x, y, d * y);
+    t3.add(x, y, d * x * y);
+}
 
-// 修改:区间加
-// 查询:单点
-struct Tbit {
+void range_add(int x, int y, int xx, int yy, ll d) {
+    add4(x, y, d);
+    add4(x, yy + 1, -d);
+    add4(xx + 1, y, -d);
+    add4(xx + 1, yy + 1, d);
+}
+
+ll get4(int x, int y) {
+    return (x + 1) * (y + 1) * t0.get(x, y)
+    - (y + 1) * t1.get(x, y)
+    - (x + 1) * t2.get(x, y)
+    + t3.get(x, y);
+}
+
+ll range_sum(int x, int y, int xx, int yy) {
+    return get4(xx, yy) - get4(x - 1, yy) - get4(xx, y - 1) + get4(x - 1, y - 1);
+}
+```
+
+### segment tree
+
++ point modify, RMQ
+
+```cpp
+// 1-indexed
+template <class S>
+struct segtree {
     int size;
-    long long t[MAXN];
+    vector<S> d;
 
-    int lowbit(int x) { return x & (-x); }
+    void pull(int p) { d[p] = op(d[p * 2], d[p * 2 + 1]); }
 
-    void init(int sz) {
-        size = sz + 1;
-        memset(t, 0, (sz + 2) * sizeof(long long));
+    segtree(int n) {
+        size = 1;
+        while (size < n) size <<= 1;
+        d.assign(2 * size, e());
     }
 
-    void add(int pos, long long val) {
-        if (pos <= 0) return;
-        while (pos <= size) {
-            t[pos] += val;
-            pos += lowbit(pos);
-        }
+    segtree(const vector<S>& v) : segtree(v.size()) {
+        copy(v.begin(), v.end(), d.begin() + size);
+        for (int i = size - 1; i >= 1; i--) pull(i);
     }
 
-    long long get(int pos) {
-        long long sum = 0;
-        while (pos > 0) {
-            sum += t[pos];
-            pos -= lowbit(pos);
-        }
-        return sum;
+    S ask(int ql, int qr, int p, int l, int r) {
+        if (ql > r || qr < l) return e();
+        if (ql <= l && qr >= r) return d[p];
+        S vl = ask(ql, qr, p * 2, l, (l + r) >> 1);
+        S vr = ask(ql, qr, p * 2 + 1, ((l + r) >> 1) + 1, r);
+        return op(vl, vr);
     }
 
-    void update(int l, int r, long long val) {
-        add(l, val);
-        add(r + 1, -val);
+    void set(int p, S x) {
+        p += size - 1;
+        d[p] = x;
+        for (p >>= 1; p > 0; p >>= 1) pull(p);
     }
+
+    S get(int p) { return d[p + size - 1]; }
+    S query(int l, int r) { return ask(l, r, 1, 1, size); }
+
+    S op(S a, S b) { return max(a, b); }
+    S e() { return -INF; }
 };
 ```
 
-### 线段树
++ point modify, kth element
 
 ```cpp
-// 下标从1开始
-// 修改:单点
-// 查询:RMQ
-struct Node {
-    int val;
-    int l, r;
-};
-struct SegT {
-#define lc (p << 1)
-#define rc (p << 1 | 1)
+int ask(ll k, int p, int l, int r) {
+    if (l == r) return l;
+    if (d[p * 2] >= k) return ask(k, p * 2, l, (l + r) >> 1);
+    return ask(k - d[p * 2], p * 2 + 1, ((l + r) >> 1) + 1, r);
+}
+
+int query(ll k) { return ask(k, 1, 1, size); }
+
+S op(S a, S b) { return a + b; }
+S e() { return 0; }
+```
 
-    const int INF = 0x3f3f3f3f;
++ range add, range sum
+
+```cpp
+template <class S, class F>
+struct lazy_segtree {
+#define args int p, int l, int r
+#define lc p * 2, l, (l + r) >> 1
+#define rc p * 2 + 1, ((l + r) >> 1) + 1, r
 
     int size;
-    Node *t;
+    vector<S> d;
+    vector<F> lz;
 
-    SegT(int sz) {
-        size = 1;
-        while (size < sz) size <<= 1;
-        t = new Node[2 * size];
-        for (int i = 1, p = size; i <= size; i++, p++) {
-            t[p].l = t[p].r = i;
-        }
-        for (int p = size - 1; p > 0; p--) {
-            t[p].l = t[lc].l;
-            t[p].r = t[rc].r;
-        }
+    void pull(int p) { d[p] = op(d[p * 2], d[p * 2 + 1]); }
+
+    void apply(F f, args) {
+        d[p] = mapping(d[p], f, l, r);
+        if (p < size) lz[p] = composition(f, lz[p]);
     }
 
-    ~SegT() {
-        delete [] t;
+    void push(args) {
+        if (lz[p] == id()) return;
+        apply(lz[p], lc);
+        apply(lz[p], rc);
+        lz[p] = id();
     }
 
-    int ask(int p, int l, int r) {
-        if (l > t[p].r || r < t[p].l) return INF;
-        if (l <= t[p].l && r >= t[p].r) return t[p].val;
-        int vl = ask(lc, l, r);
-        int vr = ask(rc, l, r);
-        return min(vl, vr);
+    S ask(int ql, int qr, args) {
+        if (ql > r || qr < l) return e();
+        if (ql <= l && qr >= r) return d[p];
+        push(p, l, r);
+        S vl = ask(ql, qr, lc);
+        S vr = ask(ql, qr, rc);
+        return op(vl, vr);
     }
 
-    void update(int k, int val) {
-        int p = size + k - 1;
-        t[p].val = val;
-        for (p >>= 1; p > 0; p >>= 1) {
-            t[p].val = min(t[lc].val, t[rc].val);
+    void modify(int ql, int qr, F f, args) {
+        if (ql > r || qr < l) return;
+        if (ql <= l && qr >= r) {
+            apply(f, p, l, r);
+            return;
         }
+        push(p, l, r);
+        modify(ql, qr, f, lc);
+        modify(ql, qr, f, rc);
+        pull(p);
     }
 
-    int query(int l, int r) { return ask(1, l, r); }
-
+#undef args
 #undef lc
 #undef rc
+
+    lazy_segtree(int n) {
+        size = 1;
+        while (size < n) size <<= 1;
+        d.assign(2 * size, e());
+        lz.assign(size, id());
+    }
+
+    lazy_segtree(const vector<S>& v) : lazy_segtree(v.size()) {
+        copy(v.begin(), v.end(), d.begin() + size);
+        for (int i = size - 1; i >= 1; i--) pull(i);
+    }
+
+    void update(int l, int r, F f) { modify(l, r, f, 1, 1, size); }
+    S query(int l, int r) { return ask(l, r, 1, 1, size); }
+
+    S op(S a, S b) { return a + b; }
+    S e() { return 0; }
+    S mapping(S a, F f, int l, int r) { return a + f * (r - l + 1); }
+    F composition(F f, F g) { return f + g; }  // f: outer function g: inner function
+    F id() { return 0; }  // in case of interval assignment, pick a value outside the data range
 };
+```
+
++ range linear transform, range sum (with modulo)
 
-// 修改:区间加
-// 查询:区间和
+```cpp
+S op(S a, S b) { return (a + b) % MOD; }
+S e() { return 0; }
+S mapping(S a, F f, int l, int r) { return (a * f.first % MOD + (r - l + 1) * f.second % MOD) % MOD; }
+F composition(F f, F g) { return F{(g.first * f.first) % MOD, (g.second * f.first % MOD + f.second) % MOD}; }
+F id() { return F{1, 0}; }
+```
+
+### dynamic segment tree (for large range values)
+
+```cpp
 struct Node {
-    int l, r;
-    long long val;
-    long long lazy;
-};
+    int lc, rc, val;
+    Node(int lc = 0, int rc = 0, int val = 0) : lc(lc), rc(rc), val(val) {}
+} t[20 * N];
+
+int cnt;
 
 struct SegT {
-#define lc (p << 1)
-#define rc (p << 1 | 1)
+#define mid ((pl + pr) >> 1)
 
-    int size;
-    Node *t;
+    int rt, size;
 
-    SegT(int sz) {
+    SegT(int sz) : rt(0) {
         size = 1;
         while (size < sz) size <<= 1;
-        t = new Node[2 * size];
-        for (int i = 1, p = size; i <= size; i++, p++) {
-            t[p].l = t[p].r = i;
-            t[p].val = t[p].lazy = 0;
-        }
-        for (int p = size - 1; p > 0; p--) {
-            t[p].l = t[lc].l;
-            t[p].r = t[rc].r;
-            t[p].val = t[p].lazy = 0;
+    }
+
+    int modify(int p, int pl, int pr, int k, int val) {
+        if (pl > k || pr < k) return p;
+        if (!p) p = ++cnt;
+        if (pl == pr) t[p].val = val;
+        else {
+            t[p].lc = modify(t[p].lc, pl, mid, k, val);
+            t[p].rc = modify(t[p].rc, mid + 1, pr, k, val);
+            t[p].val = max(t[t[p].lc].val, t[t[p].rc].val);
         }
+        return p;
     }
 
-    ~SegT() {
-        delete [] t;
+    int ask(int p, int pl, int pr, int l, int r) {
+        if (l > pr || r < pl) return -INF;
+        if (l <= pl && r >= pr) return t[p].val;
+        int vl = ask(t[p].lc, pl, mid, l, r);
+        int vr = ask(t[p].rc, mid + 1, pr, l, r);
+        return max(vl, vr);
     }
 
-    void pushdown(int p) {
-        if (!t[p].lazy) return;
-        t[lc].val += t[p].lazy * (t[lc].r - t[lc].l + 1);
-        t[rc].val += t[p].lazy * (t[rc].r - t[rc].l + 1);
-        t[lc].lazy += t[p].lazy;
-        t[rc].lazy += t[p].lazy;
-        t[p].lazy = 0;
+    void update(int k, int val) { rt = modify(rt, 1, size, k, val); }
+    int query(int l, int r) { return ask(rt, 1, size, l, r); }
+
+#undef mid
+};
+```
+
+### persistent segment tree
+
+```cpp
+struct Node {
+    int lc, rc, val;
+    Node(int lc = 0, int rc = 0, int val = 0) : lc(lc), rc(rc), val(val) {}
+} t[40 * MAXN]; // (4 + log(size)) * MAXN, attention memory limit
+
+int cnt;
+
+struct FST {
+#define mid ((pl + pr) >> 1)
+
+    int size;
+    vector<int> root;
+
+    FST(int sz) {
+        size = 1;
+        while (size < sz) size <<= 1;
+        root.push_back(N(0, 0, 0));
     }
 
-    long long ask(int p, int l, int r) {
-        if (l > t[p].r || r < t[p].l) return 0;
-        if (l <= t[p].l && r >= t[p].r) return t[p].val;
-        pushdown(p);
-        long long vl = ask(lc, l, r);
-        long long vr = ask(rc, l, r);
-        return vl + vr;
+    int N(int lc, int rc, int val) {
+        t[cnt] = Node(lc, rc, val);
+        return cnt++;
     }
 
-    void modify(int p, int l, int r, int val) {
-        if (l > t[p].r || r < t[p].l) return;
-        if (l <= t[p].l && r >= t[p].r) {
-            t[p].val += 1LL * val * (t[p].r - t[p].l + 1);
-            t[p].lazy += val;
-            return;
-        }
-        pushdown(p);
-        modify(lc, l, r, val);
-        modify(rc, l, r, val);
-        t[p].val = t[lc].val + t[rc].val;
+    int ins(int p, int pl, int pr, int x) {
+        if (pl > x || pr < x) return p;
+        if (pl == pr) return N(0, 0, t[p].val + 1);
+        return N(ins(t[p].lc, pl, mid, x), ins(t[p].rc, mid + 1, pr, x), t[p].val + 1);
     }
 
-    void update(int l, int r, int val) { modify(1, l, r, val); }
-    long long query(int l, int r) { return ask(1, l, r); }
+    int ask(int p1, int p2, int pl, int pr, int k) {
+        if (pl == pr) return pl;
+        ll vl = t[t[p2].lc].val - t[t[p1].lc].val;
+        if (k <= vl) return ask(t[p1].lc, t[p2].lc, pl, mid, k);
+        return ask(t[p1].rc, t[p2].rc, mid + 1, pr, k - vl);
+    }
 
-#undef lc
-#undef rc
+    void add(int x) {
+        root.push_back(ins(root.back(), 1, size, x));
+    }
+
+    int query(int l, int r, int k) {
+        return ask(root[l - 1], root[r], 1, size, k);
+    }
+
+#undef mid
 };
+```
 
-// 修改:区间加
-// 查询:RMQ
-const long long INF = 0x3f3f3f3f3f3f3f3f;
-
-void pushdown(int p) {
-    if (!t[p].lazy) return;
-    t[lc].val += t[p].lazy;
-    t[rc].val += t[p].lazy;
-    t[lc].lazy += t[p].lazy;
-    t[rc].lazy += t[p].lazy;
-    t[p].lazy = 0;
-}
+### Splay
 
-long long ask(int p, int l, int r) {
-    if (l > t[p].r || r < t[p].l) return INF;
-    if (l <= t[p].l && r >= t[p].r) return t[p].val;
-    pushdown(p);
-    long long vl = ask(lc, l, r);
-    long long vr = ask(rc, l, r);
-    return min(vl, vr);
-}
+```cpp
+// normal Splay
+struct Node {
+    int val, size;
+    Node *pa, *lc, *rc;
+    Node(int val = 0, Node *pa = nullptr) : val(val), size(1), pa(pa), lc(nullptr), rc(nullptr) {}
+    Node*& c(bool x) { return x ? lc : rc; }
+    bool d() { return pa ? this == pa->lc : 0; }
+} pool[MAXN << 2], *tail = pool;
 
-void modify(int p, int l, int r, int val) {
-    if (l > t[p].r || r < t[p].l) return;
-    if (l <= t[p].l && r >= t[p].r) {
-        t[p].val += val;
-        t[p].lazy += val;
-        return;
-    }
-    pushdown(p);
-    modify(lc, l, r, val);
-    modify(rc, l, r, val);
-    t[p].val = min(t[lc].val, t[rc].val);
-}
+struct Splay {
+    Node *root;
 
-// 修改:区间赋值
-// 查询:区间和
-void pushdown(int p) {
-    if (!t[p].lazy) return;
-    t[lc].val = t[p].lazy * (t[lc].r - t[lc].l + 1);
-    t[rc].val = t[p].lazy * (t[rc].r - t[rc].l + 1);
-    t[lc].lazy = t[p].lazy;
-    t[rc].lazy = t[p].lazy;
-    t[p].lazy = 0;
-}
+    Splay() : root(nullptr) {}
 
-long long ask(int p, int l, int r) {
-    if (l > t[p].r || r < t[p].l) return 0;
-    if (l <= t[p].l && r >= t[p].r) return t[p].val;
-    pushdown(p);
-    long long vl = ask(lc, l, r);
-    long long vr = ask(rc, l, r);
-    return vl + vr;
-}
+    Node* N(int val, Node *pa) {
+        return new (tail++) Node(val, pa);
+    }
 
-void modify(int p, int l, int r, int val) {
-    if (l > t[p].r || r < t[p].l) return;
-    if (l <= t[p].l && r >= t[p].r) {
-        t[p].val = 1LL * val * (t[p].r - t[p].l + 1);
-        t[p].lazy = val;
-        return;
-    }
-    pushdown(p);
-    modify(lc, l, r, val);
-    modify(rc, l, r, val);
-    t[p].val = t[lc].val + t[rc].val;
-}
- 
-// 修改:区间乘混加
-// 查询:区间和取模
-struct Node {
-    int l, r;
-    long long val, mul, add;
-};
+    void upd(Node *o) {
+        o->size = (o->lc ? o->lc->size : 0) + (o->rc ? o->rc->size : 0) + 1;
+    }
 
-struct SegT {
-#define lc (p << 1)
-#define rc (p << 1 | 1)
+    void link(Node *x, Node *y, bool d) {
+        if (x) x->pa = y;
+        if (y) y->c(d) = x;
+    }
 
-    int size;
-    Node *t;
+    void rotate(Node *o) {
+        bool dd = o->d();
+        Node *x = o->pa, *xx = x->pa, *y = o->c(!dd);
+        link(o, xx, x->d());
+        link(y, x, dd);
+        link(x, o, !dd);
+        upd(x);
+        upd(o);
+    }
 
-    SegT(int sz) {
-        size = 1;
-        while (size < sz) size <<= 1;
-        t = new Node[2 * size];
-        for (int i = 1, p = size; i <= size; i++, p++) {
-            t[p].l = t[p].r = i;
-            t[p].val = t[p].add = 0;
-            t[p].mul = 1;
-        }
-        for (int p = size - 1; p > 0; p--) {
-            t[p].l = t[lc].l;
-            t[p].r = t[rc].r;
-            t[p].val = t[p].add = 0;
-            t[p].mul = 1;
+    void splay(Node *o) {
+        for (Node *x = o->pa; x = o->pa, x; rotate(o)) {
+            if (x->pa) rotate(o->d() == x->d() ? x : o);
         }
+        root = o;
     }
+};
+```
 
-    ~SegT() {
-        delete [] t;
+### Treap
+
+```cpp
+// split_x left elements < x
+// split_k left side has k elements
+namespace tr {
+    using uint = unsigned int;
+
+    uint rnd() {
+        static uint A = 1 << 16 | 3, B = 33333331, C = 1091;
+        return C = A * C + B;
     }
 
-    void pushdown(int p) {
-        if (t[p].mul == 1 && t[p].add == 0) return;
-        t[lc].val = (t[lc].val * t[p].mul % MOD + (t[lc].r - t[lc].l + 1) * t[p].add % MOD) % MOD;
-        t[rc].val = (t[rc].val * t[p].mul % MOD + (t[rc].r - t[rc].l + 1) * t[p].add % MOD) % MOD;
-        t[lc].mul = t[p].mul * t[lc].mul % MOD;
-        t[rc].mul = t[p].mul * t[rc].mul % MOD;
-        t[lc].add = (t[lc].add * t[p].mul % MOD + t[p].add) % MOD;
-        t[rc].add = (t[rc].add * t[p].mul % MOD + t[p].add) % MOD;
-        t[p].mul = 1;
-        t[p].add = 0;
+    struct Node {
+        uint key;
+        int val, size;
+        Node *lc, *rc;
+        Node(int val = 0) : key(rnd()), val(val), size(1), lc(nullptr), rc(nullptr) {}
+    } pool[MAXN << 2], *tail = pool;
+
+    Node* N(int val) {
+        return new (tail++) Node(val);
     }
 
-    long long ask(int p, int l, int r) {
-        if (l > t[p].r || r < t[p].l) return 0;
-        if (l <= t[p].l && r >= t[p].r) return t[p].val;
-        pushdown(p);
-        long long vl = ask(lc, l, r);
-        long long vr = ask(rc, l, r);
-        return (vl + vr) % MOD;
+    void upd(Node *o) {
+        o->size = (o->lc ? o->lc->size : 0) + (o->rc ? o->rc->size : 0) + 1;
     }
 
-    // x' = ax + b
-    void modify(int p, int l, int r, int a, int b) {
-        if (l > t[p].r || r < t[p].l) return;
-        if (l <= t[p].l && r >= t[p].r) {
-            t[p].val = (t[p].val * a % MOD + (t[p].r - t[p].l + 1) * b % MOD) % MOD;
-            t[p].mul = t[p].mul * a % MOD;
-            t[p].add = (t[p].add * a % MOD + b) % MOD;
-            return;
+    Node* merge(Node *l, Node *r) {
+        if (!l) return r;
+        if (!r) return l;
+        if (l->key > r->key) {
+            l->rc = merge(l->rc, r);
+            upd(l);
+            return l;
+        } else {
+            r->lc = merge(l, r->lc);
+            upd(r);
+            return r;
         }
-        pushdown(p);
-        modify(lc, l, r, a, b);
-        modify(rc, l, r, a, b);
-        t[p].val = (t[lc].val + t[rc].val) % MOD;
     }
 
-    void update(int l, int r, int a, int b) { modify(1, l, r, a, b); }
-    long long query(int l, int r) { return ask(1, l, r); }
+    void split_x(Node *o, int x, Node*& l, Node*& r) {
+        if (!o) { l = r = nullptr; return; }
+        if (o->val < x) {
+            l = o;
+            split_x(o->rc, x, l->rc, r);
+            upd(l);
+        } else {
+            r = o;
+            split_x(o->lc, x, l, r->lc);
+            upd(r);
+        }
+    }
 
-#undef lc
-#undef rc
+    void split_k(Node *o, int k, Node*& l, Node*& r) {
+        if (!o) { l = r = nullptr; return; }
+        int lsize = o->lc ? o->lc->size : 0;
+        if (lsize < k) {
+            l = o;
+            split_k(o->rc, k - lsize - 1, o->rc, r);
+            upd(l);
+        } else {
+            r = o;
+            split_k(o->lc, k, l, o->lc);
+            upd(r);
+        }
+    }
+}
+```
+
+### interval set
+
+```cpp
+// for Q assign operation it takes Qlogn time in total
+template <class T>
+struct interval_set {
+    map<pair<int, int>, T> mp;  // {r,l}=val
+    interval_set(int l, int r, T v = T()) { mp[{r, l}] = v; }
+
+    // assign a[i]=val for l<=i<=r
+    // returns affected ranges before performing this assign operation
+    vector<pair<pair<int, int>, T>> assign(int l, int r, T v) {
+        auto b = mp.lower_bound({l, 0})->first;
+        if (b.second != l) {
+            T z = mp[b];
+            mp.erase(b);
+            mp[{l - 1, b.second}] = z;
+            mp[{b.first, l}] = z;
+        }
+
+        auto e = mp.lower_bound({r, 0})->first;
+        if (e.first != r) {
+            T z = mp[e];
+            mp.erase(e);
+            mp[{e.first, r + 1}] = z;
+            mp[{r, e.second}] = z;
+        }
+
+        vector<pair<pair<int, int>, T>> ret;
+        for (auto it = mp.lower_bound({l, 0}); it != mp.end() && it->first.first <= r; ++it) {
+            ret.push_back({{it->first.second, it->first.first}, it->second});
+        }
+        for (auto it : ret) mp.erase({it.first.second, it.first.first});
+        mp[{r, l}] = v;
+        return ret;
+    }
+
+    T operator[](int i) const { return mp.lower_bound({i, 0})->second; }
 };
 ```
+
+### CDQ Divide-and-Conquer
+
++ 3D partial order (not strict)
+
+```cpp
+struct Node {
+    int x, y, z, sum, ans;
+} p[N], q[N];
+
+void CDQ(int l, int r) {
+    if (l == r) return;
+    int mid = (l + r) >> 1;
+    CDQ(l, mid);
+    CDQ(mid + 1, r);
+    int i = l, j = mid + 1;
+    for (int t = l; t <= r; t++) {
+        if (j > r || (i <= mid && p[i].y <= p[j].y)) {
+            q[t] = p[i++];
+            bit.add(q[t].z, q[t].sum);
+        } else {
+            q[t] = p[j++];
+            q[t].ans += bit.get(q[t].z);
+        }
+    }
+    for (i = l; i <= r; i++) {
+        p[i] = q[i];
+        bit.update(p[i].z, 0);
+    }
+}
+
+void go() {
+    sort(p + 1, p + n + 1, [](const Node &a, const Node &b) {
+        if (a.x != b.x) return a.x < b.x;
+        if (a.y != b.y) return a.y < b.y;
+        return a.z < b.z;
+    });
+    auto eq = [](const Node& a, const Node& b) {
+        return a.x == b.x && a.y == b.y && a.z == b.z;
+    };
+    int k = n;
+    for (int i = 1, j = 1; i <= n; i++, j++) {
+        if (eq(p[i], p[j - 1])) j--, k--;
+        else if (i != j) p[j] = p[i];
+        p[j].sum++;
+    }
+    bit.init(m);
+    CDQ(1, k);
+}
+```
diff --git a/2-Graph.md b/2-Graph.md
new file mode 100644
index 0000000..40b1959
--- /dev/null
+++ b/2-Graph.md
@@ -0,0 +1,677 @@
+## Graph Theory
+
+### adjacency table with linked list
+
+```cpp
+int ecnt, mp[N];
+
+struct Edge {
+    int to, nxt;
+    Edge(int to = 0, int nxt = 0) : to(to), nxt(nxt) {}
+} es[M];
+
+void mp_init() {
+    memset(mp, -1, (n + 2) * sizeof(int));
+    ecnt = 0;
+}
+
+void mp_link(int u, int v) {
+    es[ecnt] = Edge(v, mp[u]);
+    mp[u] = ecnt++;
+}
+
+for (int i = mp[u]; i != -1; i = es[i].nxt)
+```
+
+### shortest path
+
++ Dijkstra
+
+```cpp
+struct Edge {
+    int to, val;
+    Edge(int to = 0, int val = 0) : to(to), val(val) {}
+};
+
+vector<Edge> G[N];
+ll dis[N];
+
+void dijkstra(int s) {
+    using pii = pair<ll, int>;
+    memset(dis, 0x3f, sizeof(dis));
+    priority_queue<pii, vector<pii>, greater<pii> > q;
+    dis[s] = 0;
+    q.emplace(0, s);
+    while (!q.empty()) {
+        pii p = q.top();
+        q.pop();
+        int u = p.second;
+        if (dis[u] < p.first) continue;
+        for (Edge& e : G[u]) {
+            int v = e.to;
+            if (umin(dis[v], dis[u] + e.val)) {
+                q.emplace(dis[v], v);
+            }
+        }
+    }
+}
+```
+
++ Bellman-Ford (aka SPFA)
+
+```cpp
+void spfa(int s) {
+    queue<int> q;
+    q.push(s);
+    memset(dis, 0x3f, sizeof(dis));
+    memset(in, 0, sizeof(in));
+    in[s] = 1;
+    dis[s] = 0;
+    while (!q.empty()) {
+        int u = q.front();
+        q.pop();
+        for (Edge& e : G[u]) {
+            int v = e.to;
+            if (dis[v] > dis[u] + e.val) {
+                dis[v] = dis[u] + e.val;
+                if (!in[v]) {
+                    in[v] = 1;
+                    q.push(v);
+                }
+            }
+        }
+        in[u] = 0;
+    }
+}
+```
+
++ Floyd, with shortest cycles
+
+```cpp
+// Note: INF cannot exceed 1/3 LLONG_MAX
+for (int k = 0; k < n; k++) {
+    for (int i = 0; i < k; i++) {
+        for (int j = 0; j < i; j++) {
+            ans = min(ans, G[i][k] + G[k][j] + dis[i][j]);
+        }
+    }
+    for (int i = 0; i < n; i++) {
+        for (int j = 0; j < n; j++) {
+            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
+        }
+    }
+}
+```
+
+### topological sort
+
+```cpp
+int n, deg[N], dis[N];
+vector<int> G[N];
+
+bool topo(vector<int>& ans) {
+    queue<int> q;
+    for (int i = 1; i <= n; i++) {
+        if (deg[i] == 0) {
+            q.push(i);
+            dis[i] = 1;
+        }
+    }
+    while (!q.empty()) {
+        int u = q.front();
+        q.pop();
+        ans.push_back(u);
+        for (int v : G[u]) {
+            deg[v]--;
+            dis[v] = max(dis[v], dis[u] + 1);
+            if (deg[v] == 0) q.push(v);
+        }
+    }
+    return ans.size() == n;
+}
+```
+
+### minimum spanning tree
+
+```cpp
+// prerequisite: dsu
+struct Edge {
+    int from, to, val;
+    Edge(int from = 0, int to = 0, int val = 0) : from(from), to(to), val(val) {}
+};
+
+vector<Edge> es;
+
+ll kruskal() {
+    sort(es.begin(), es.end(), [](Edge& x, Edge& y) { return x.val < y.val; });
+    iota(pa, pa + n + 1, 0);
+    ll ans = 0;
+    for (Edge& e : es) {
+        if (find(e.from) != find(e.to)) {
+            merge(e.from, e.to);
+            ans += e.val;
+        }
+    }
+    return ans;
+}
+```
+
+### LCA
+
+```cpp
+int dep[N], up[N][22]; // 22 = ((int)log2(N) + 1)
+
+void dfs(int u, int pa) {
+    dep[u] = dep[pa] + 1;
+    up[u][0] = pa;
+    for (int i = 1; i < 22; i++) {
+        up[u][i] = up[up[u][i - 1]][i - 1];
+    }
+    for (int v : G[u]) {
+        if (v != pa) dfs(v, u);
+    }
+}
+
+int lca(int u, int v) {
+    if (dep[u] > dep[v]) swap(u, v);
+    int t = dep[v] - dep[u];
+    for (int i = 0; i < 22; i++) {
+        if ((t >> i) & 1) v = up[v][i];
+    }
+    if (u == v) return u;
+    for (int i = 21; i >= 0; i--) {
+        if (up[u][i] != up[v][i]) {
+            u = up[u][i];
+            v = up[v][i];
+        }
+    }
+    return up[u][0];
+}
+```
+
+### flow network
+
++ max flow
+
+```cpp
+const int INF = 0x7fffffff;
+
+struct Dinic {
+    struct Edge {
+        int to, cap;
+        Edge(int to, int cap) : to(to), cap(cap) {}
+    };
+
+    int n, s, t;
+    vector<Edge> es;
+    vector<vector<int> > G;
+    vector<int> dis, cur;
+
+    Dinic(int n, int s, int t) : n(n), s(s), t(t), G(n + 1), dis(n + 1), cur(n + 1) {}
+
+    void add_edge(int u, int v, int cap) {
+        G[u].push_back(es.size());
+        es.emplace_back(v, cap);
+        G[v].push_back(es.size());
+        es.emplace_back(u, 0);
+    }
+
+    bool bfs() {
+        dis.assign(n + 1, 0);
+        queue<int> q;
+        q.push(s);
+        dis[s] = 1;
+        while (!q.empty()) {
+            int u = q.front();
+            q.pop();
+            for (int i : G[u]) {
+                Edge& e = es[i];
+                if (!dis[e.to] && e.cap > 0) {
+                    dis[e.to] = dis[u] + 1;
+                    q.push(e.to);
+                }
+            }
+        }
+        return dis[t];
+    }
+
+    int dfs(int u, int cap) {
+        if (u == t || cap == 0) return cap;
+        int tmp = cap, f;
+        for (int& i = cur[u]; i < (int)G[u].size(); i++) {
+            Edge& e = es[G[u][i]];
+            if (dis[e.to] == dis[u] + 1) {
+                f = dfs(e.to, min(cap, e.cap));
+                e.cap -= f;
+                es[G[u][i] ^ 1].cap += f;
+                cap -= f;
+                if (cap == 0) break;
+            }
+        }
+        return tmp - cap;
+    }
+
+    ll solve() {
+        ll flow = 0;
+        while (bfs()) {
+            cur.assign(n + 1, 0);
+            flow += dfs(s, INF);
+        }
+        return flow;
+    }
+};
+```
+
++ min-cost max flow
+
+```cpp
+const ll INF = 1e15;
+
+struct MCMF {
+    struct Edge {
+        int from, to;
+        ll cap, cost;
+        Edge(int from, int to, ll cap, ll cost) : from(from), to(to), cap(cap), cost(cost) {}
+    };
+
+    int n, s, t;
+    ll flow, cost;
+    vector<Edge> es;
+    vector<vector<int> > G;
+    vector<ll> d, a;  // dis, add, prev
+    vector<int> p, in;
+
+    MCMF(int n, int s, int t) : n(n), s(s), t(t), flow(0), cost(0), G(n + 1), p(n + 1), a(n + 1) {}
+
+    void add_edge(int u, int v, ll cap, ll cost) {
+        G[u].push_back(es.size());
+        es.emplace_back(u, v, cap, cost);
+        G[v].push_back(es.size());
+        es.emplace_back(v, u, 0, -cost);
+    }
+
+    bool spfa() {
+        d.assign(n + 1, INF);
+        in.assign(n + 1, 0);
+        d[s] = 0;
+        in[s] = 1;
+        a[s] = INF;
+        queue<int> q;
+        q.push(s);
+        while (!q.empty()) {
+            int u = q.front();
+            q.pop();
+            in[u] = 0;
+            for (int& i : G[u]) {
+                Edge& e = es[i];
+                if (e.cap && d[e.to] > d[u] + e.cost) {
+                    d[e.to] = d[u] + e.cost;
+                    p[e.to] = i;
+                    a[e.to] = min(a[u], e.cap);
+                    if (!in[e.to]) {
+                        q.push(e.to);
+                        in[e.to] = 1;
+                    }
+                }
+            }
+        }
+        return d[t] != INF;
+    }
+
+    void solve() {
+        while (spfa()) {
+            flow += a[t];
+            cost += a[t] * d[t];
+            int u = t;
+            while (u != s) {
+                es[p[u]].cap -= a[t];
+                es[p[u] ^ 1].cap += a[t];
+                u = es[p[u]].from;
+            }
+        }
+    }
+};
+```
+
+### undirected graph min-cut
+
+```cpp
+namespace stoer_wagner {
+    bool vis[N], in[N];
+    int G[N][N], w[N];
+
+    void init() {
+        memset(G, 0, sizeof(G));
+        memset(in, 0, sizeof(in));
+    }
+
+    void add_edge(int u, int v, int w) {
+        G[u][v] += w;
+        G[v][u] += w;
+    }
+
+    int search(int& s, int& t) {
+        memset(vis, 0, sizeof(vis));
+        memset(w, 0, sizeof(w));
+        int maxw, tt = n + 1;
+        for (int i = 0; i < n; i++) {
+            maxw = -INF;
+            for (int j = 0; j < n; j++) {
+                if (!in[j] && !vis[j] && w[j] > maxw) {
+                    maxw = w[j];
+                    tt = j;
+                }
+            }
+            if (t == tt) return w[t];
+            s = t; t = tt;
+            vis[tt] = true;
+            for (int j = 0; j < n; j++) {
+                if (!in[j] && !vis[j]) {
+                    w[j] += G[tt][j];
+                }
+            }
+        }
+        return w[t];
+    }
+
+    int go() {
+        int s, t, ans = INF;
+        for (int i = 0; i < n - 1; i++) {
+            s = t = -1;
+            ans = min(ans, search(s, t));
+            if (ans == 0) return 0;
+            in[t] = true;
+            for (int j = 0; j < n; j++) {
+                if (!in[j]) {
+                    G[s][j] += G[t][j];
+                    G[j][s] += G[j][t];
+                }
+            }
+        }
+        return ans;
+    }
+}
+```
+
+### heavy-light decomposition
+
+```cpp
+// weights on vertices
+vector<int> G[N];
+int pa[N], sz[N], dep[N], dfn[N], maxc[N], top[N], clk;
+
+void dfs1(int u) {
+    sz[u] = 1;
+    maxc[u] = -1;
+    int maxs = 0;
+    for (int& v : G[u]) {
+        if (v != pa[u]) {
+            pa[v] = u;
+            dep[v] = dep[u] + 1;
+            dfs1(v);
+            sz[u] += sz[v];
+            if (umax(maxs, sz[v])) maxc[u] = v;
+        }
+    }
+}
+
+void dfs2(int u, int tp) {
+    top[u] = tp;
+    dfn[u] = ++clk;
+    if (maxc[u] != -1) dfs2(maxc[u], tp);
+    for (int& v : G[u]) {
+        if (v != pa[u] && v != maxc[u]) {
+            dfs2(v, v);
+        }
+    }
+}
+
+void init() {
+    clk = 0;
+    dep[1] = 1;
+    dfs1(1);
+    dfs2(1, 1);
+}
+
+ll go(int u, int v) {
+    int uu = top[u], vv = top[v];
+    ll res = 0;
+    while (uu != vv) {
+        if (dep[uu] < dep[vv]) {
+            swap(u, v);
+            swap(uu, vv);
+        }
+        res += segt.query(dfn[uu], dfn[u]);
+        u = pa[uu];
+        uu = top[u];
+    }
+    if (dep[u] > dep[v]) swap(u, v);
+    res += segt.query(dfn[u], dfn[v]);
+    return res;
+}
+```
+
+### Tarjan
+
++ cut-point
+
+```cpp
+int dfn[N], low[N], clk;
+
+void init() { clk = 0; memset(dfn, 0, sizeof(dfn)); }
+
+void tarjan(int u, int pa) {
+    low[u] = dfn[u] = ++clk;
+    int cc = (pa != 0);
+    for (int v : G[u]) {
+        if (v == pa) continue;
+        if (!dfn[v]) {
+            tarjan(v, u);
+            low[u] = min(low[u], low[v]);
+            cc += low[v] >= dfn[u];
+        } else low[u] = min(low[u], dfn[v]);
+    }
+    if (cc > 1) // ...
+}
+```
+
++ cut-edge (aka bridge)
+
+```cpp
+int dfn[N], low[N], clk;
+
+void init() { clk = 0; memset(dfn, 0, sizeof(dfn)); }
+
+void tarjan(int u, int pa) {
+    low[u] = dfn[u] = ++clk;
+    int f = 0;
+    for (int v : G[u]) {
+        if (v == pa && ++f == 1) continue;
+        if (!dfn[v]) {
+            tarjan(v, u);
+            if (low[v] > dfn[u]) // ...
+            low[u] = min(low[u], low[v]);
+        } else low[u] = min(low[u], dfn[v]);
+    }
+}
+```
+
++ strongly connected component
+
+```cpp
+int dfn[N], low[N], clk, tot, color[N];
+vector<int> scc[N];
+
+void init() { tot = clk = 0; memset(dfn, 0, sizeof dfn); }
+
+void tarjan(int u) {
+    static int st[N], p;
+    static bool in[N];
+    dfn[u] = low[u] = ++clk;
+    st[p++] = u;
+    in[u] = true;
+    for (int v : G[u]) {
+        if (!dfn[v]) {
+            tarjan(v);
+            low[u] = min(low[u], low[v]);
+        } else if (in[v]) {
+            low[u] = min(low[u], dfn[v]);
+        }
+    }
+    if (dfn[u] == low[u]) {
+        ++tot;
+        for (;;) {
+            int x = st[--p];
+            in[x] = false;
+            color[x] = tot;
+            scc[tot].push_back(x);
+            if (x == u) break;
+        }
+    }
+}
+```
+
++ 2-SAT
+
+```cpp
+// N needs to be 2x
+void two_sat() {
+    for (int i = 1; i <= n * 2; i++) {
+        if (!dfn[i]) tarjan(i);
+    }
+    for (int i = 1; i <= n; i++) {
+        if (color[i] == color[i + n]) {
+            // impossible
+        }
+    }
+    for (int i = 1; i <= n; i++) {
+        if (color[i] < color[i + n]) {
+            // select
+        }
+    }
+}
+```
+
+### dominant tree
+
++ DAG
+
+```cpp
+// rt is the vertex where the indegree is 0 (may need a super source vertex)
+int n, deg[N], dep[N], up[N][22];
+vector<int> G[N], rG[N], dt[N];
+
+bool topo(vector<int>& ans, int rt) {
+    queue<int> q;
+    q.push(rt);
+    while (!q.empty()) {
+        int u = q.front();
+        q.pop();
+        ans.push_back(u);
+        for (int v : G[u]) {
+            deg[v]--;
+            if (deg[v] == 0) q.push(v);
+        }
+    }
+    return ans.size() == n;
+}
+
+int lca(int u, int v) {
+    if (dep[u] > dep[v]) swap(u, v);
+    int t = dep[v] - dep[u];
+    for (int i = 0; i < 22; i++) {
+        if ((t >> i) & 1) v = up[v][i];
+    }
+    if (u == v) return u;
+    for (int i = 21; i >= 0; i--) {
+        if (up[u][i] != up[v][i]) {
+            u = up[u][i];
+            v = up[v][i];
+        }
+    }
+    return up[u][0];
+}
+
+void go(int rt) {
+    vector<int> a;
+    topo(a, rt);
+    dep[rt] = 1;
+    for (int i = 1; i < a.size(); i++) {
+        int u = a[i], pa = -1;
+        for (int v : rG[u]) {
+            pa = (pa == -1) ? v : lca(pa, v);
+        }
+        dt[pa].push_back(u);
+        dep[u] = dep[pa] + 1;
+        up[u][0] = pa;
+        for (int i = 1; i < 22; i++) {
+            up[u][i] = up[up[u][i - 1]][i - 1];
+        }
+    }
+}
+```
+
++ general directed graph
+
+```cpp
+vector<int> G[N], rG[N];
+vector<int> dt[N];
+
+namespace tl {
+    int pa[N], dfn[N], clk, rdfn[N];
+    int c[N], best[N], sdom[N], idom[N];
+
+    void init(int n) {
+        clk = 0;
+        fill(c, c + n + 1, -1);
+        fill(dfn, dfn + n + 1, 0);
+        for (int i = 1; i <= n; i++) {
+            dt[i].clear();
+            sdom[i] = best[i] = i;
+        }
+    }
+
+    void dfs(int u) {
+        dfn[u] = ++clk;
+        rdfn[clk] = u;
+        for (int& v: G[u]) {
+            if (!dfn[v]) {
+                pa[v] = u;
+                dfs(v);
+            }
+        }
+    }
+
+    int fix(int x) {
+        if (c[x] == -1) return x;
+        int& f = c[x], rt = fix(f);
+        if (dfn[sdom[best[x]]] > dfn[sdom[best[f]]]) best[x] = best[f];
+        return f = rt;
+    }
+
+    void go(int rt) {
+        dfs(rt);
+        for (int i = clk; i > 1; i--) {
+            int x = rdfn[i], mn = clk + 1;
+            for (int& u: rG[x]) {
+                if (!dfn[u]) continue; // may not reach all vertices
+                fix(u);
+                mn = min(mn, dfn[sdom[best[u]]]);
+            }
+            c[x] = pa[x];
+            dt[sdom[x] = rdfn[mn]].push_back(x);
+            x = rdfn[i - 1];
+            for (int& u: dt[x]) {
+                fix(u);
+                idom[u] = (sdom[best[u]] == x) ? x : best[u];
+            }
+            dt[x].clear();
+        }
+        for (int i = 2; i <= clk; i++) {
+            int u = rdfn[i];
+            if (idom[u] != sdom[u]) idom[u] = idom[idom[u]];
+            dt[idom[u]].push_back(u);
+        }
+    }
+}
+```
diff --git a/3-String.md b/3-String.md
new file mode 100644
index 0000000..190005b
--- /dev/null
+++ b/3-String.md
@@ -0,0 +1,426 @@
+## String
+
+### substring hash
+
+```cpp
+// don't use hash in open hack
+using ull = unsigned long long;
+
+const int x = 135, p = 1e9 + 9;
+
+ull xp[N];
+
+void init_xp() {
+    xp[0] = 1;
+    for (int i = 1; i < N; i++) {
+        xp[i] = xp[i - 1] * x % p;
+    }
+}
+
+struct Hash {
+    vector<ull> h;
+
+    Hash() : h(1) {}
+
+    void add(const string &s) {
+        ull res = h.back();
+        for (char c : s) {
+            res = (res * x + c) % p;
+            h.push_back(res);
+        }
+    }
+
+    // 0-indexed, [l, r]
+    ull get(int l, int r) {
+        r++;
+        return (h[r] - h[l] * xp[r - l] % p + p) % p;
+    }
+};
+```
+
++ double hash
+
+```cpp
+const int x = 135, p1 = 1e9 + 7, p2 = 1e9 + 9;
+const ull mask32 = ~(0u);
+
+ull xp1[N], xp2[N];
+
+void init_xp() {
+    xp1[0] = xp2[0] = 1;
+    for (int i = 1; i < N; i++) {
+        xp1[i] = xp1[i - 1] * x % p1;
+        xp2[i] = xp2[i - 1] * x % p2;
+    }
+}
+
+struct Hash {
+    vector<ull> h;
+
+    Hash() : h(1) {}
+
+    void add(const string& s) {
+        ull res1 = h.back() >> 32;
+        ull res2 = h.back() & mask32;
+        for (char c : s) {
+            res1 = (res1 * x + c) % p1;
+            res2 = (res2 * x + c) % p2;
+            h.push_back((res1 << 32) | res2);
+        }
+    }
+
+    // 0-indexed, [l, r]
+    ull get(int l, int r) {
+        r++;
+        int len = r - l;
+        ull l1 = h[l] >> 32, r1 = h[r] >> 32;
+        ull l2 = h[l] & mask32, r2 = h[r] & mask32;
+        ull res1 = (r1 - l1 * xp1[len] % p1 + p1) % p1;
+        ull res2 = (r2 - l2 * xp2[len] % p2 + p2) % p2;
+        return (res1 << 32) | res2;
+    }
+};
+```
+
++ 2D hash
+
+```cpp
+const ll basex = 239, basey = 241, p = 998244353;
+
+ll pwx[N], pwy[N];
+
+void init_xp() {
+    pwx[0] = pwy[0] = 1;
+    for (int i = 1; i < N; i++) {
+        pwx[i] = pwx[i - 1] * basex % p;
+        pwy[i] = pwy[i - 1] * basey % p;
+    }
+}
+
+struct Hash2D {
+    vector<vector<ll> > h;
+
+    Hash2D(const vector<vector<int> >& a, int n, int m) : h(n + 1, vector<ll>(m + 1)) {
+        for (int i = 0; i < n; i++) {
+            ll s = 0;
+            for (int j = 0; j < m; j++) {
+                s = (s * basey + a[i][j] + 1) % p;
+                h[i + 1][j + 1] = (h[i][j + 1] * basex + s) % p;
+            }
+        }
+    }
+
+    ll get(int x, int y, int xx, int yy) {
+        ++xx; ++yy;
+        int dx = xx - x, dy = yy - y;
+        ll res = h[xx][yy]
+            - h[x][yy] * pwx[dx]
+            - h[xx][y] * pwy[dy]
+            + h[x][y] * pwx[dx] % p * pwy[dy];
+        return (res % p + p) % p;
+    }
+};
+```
+
+### Manacher
+
+```cpp
+// "aba" => "#a#b#a#"
+struct Manacher {
+    vector<int> d;
+
+    Manacher(const string& s) {
+        string t = "#";
+        for (int i = 0; i < s.size(); i++) {
+            t.push_back(s[i]);
+            t.push_back('#');
+        }
+        int n = t.size();
+        d.resize(n);
+        for (int i = 0, l = 0, r = -1; i < n; i++) {
+            int k = (i > r) ? 1 : min(d[l + r - i], r - i);
+            while (i - k >= 0 && i + k < n && t[i - k] == t[i + k]) k++;
+            d[i] = --k;
+            if (i + k > r) {
+                l = i - k;
+                r = i + k;
+            }
+        }
+    }
+
+    // 0-indexed [l, r]
+    bool is_p(int l, int r) { return d[l + r + 1] >= r - l + 1; }
+};
+```
+
+### KMP
+
+```cpp
+// prefix function (the longest common prefix and suffix for each prefix)
+vector<int> get_pi(const string& s) {
+    int n = s.size(), j = 0;
+    vector<int> a(n);
+    for (int i = 1; i < n; i++) {
+        while (j && s[j] != s[i]) j = a[j - 1];
+        if (s[j] == s[i]) j++;
+        a[i] = j;
+    }
+    return a;
+}
+
+void kmp(const string& s, vector<int>& a, const string& t) {
+    int j = 0;
+    for (int i = 0; i < t.size(); i++) {
+        while (j && s[j] != t[i]) j = a[j - 1];
+        if (s[j] == t[i]) j++;
+        if (j == s.size()) {
+            // ...
+            j = a[j - 1]; // allow overlap, j = 0 if not allowed
+        }
+    }
+}
+
+// Z function, z[i] = LCP(s, s[i:])
+vector<int> get_z(const string& s) {
+    int n = s.size(), l = 0, r = 0;
+    vector<int> z(n);
+    for (int i = 1; i < n; i++) {
+        if (i <= r) z[i] = min(r - i + 1, z[i - l]);
+        while (i + z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++;
+        if (i + z[i] - 1 > r) {
+            l = i;
+            r = i + z[i] - 1;
+        }
+    }
+    return z;
+}
+```
+
+### lexicographically minimal string rotation
+
+```cpp
+int get(const string& s) {
+    int k = 0, i = 0, j = 1, n = s.size();
+    while (k < n && i < n && j < n) {
+        if (s[(i + k) % n] == s[(j + k) % n]) {
+            k++;
+        } else {
+            s[(i + k) % n] > s[(j + k) % n] ? i = i + k + 1 : j = j + k + 1;
+            if (i == j) i++;
+            k = 0;
+        }
+    }
+    return min(i, j);
+}
+```
+
+### Trie
+
+```cpp
+// binary Trie
+struct Trie {
+    int t[31 * N][2], sz;
+
+    void init() {
+        memset(t, 0, 2 * (sz + 2) * sizeof(int));
+        sz = 1;
+    }
+
+    void insert(int x) {
+        int p = 0;
+        for (int i = 30; i >= 0; i--) {
+            bool d = (x >> i) & 1;
+            if (!t[p][d]) t[p][d] = sz++;
+            p = t[p][d];
+        }
+    }
+};
+
+// normal Trie
+struct Trie {
+    int t[N][26], sz, cnt[N];
+
+    void init() {
+        memset(t, 0, 26 * (sz + 2) * sizeof(int));
+        memset(cnt, 0, (sz + 2) * sizeof(int));
+        sz = 1;
+    }
+
+    void insert(const string& s) {
+        int p = 0;
+        for (char c : s) {
+            int d = c - 'a';
+            if (!t[p][d]) t[p][d] = sz++;
+            p = t[p][d];
+        }
+        cnt[p]++;
+    }
+};
+```
+
+### Aho-Corasick
+
+```cpp
+struct ACA {
+    int t[N][26], sz, fail[N], nxt[N], cnt[N];
+
+    void init() {
+        memset(t, 0, 26 * (sz + 2) * sizeof(int));
+        memset(fail, 0, (sz + 2) * sizeof(int));
+        memset(nxt, 0, (sz + 2) * sizeof(int));
+        memset(cnt, 0, (sz + 2) * sizeof(int));
+        sz = 1;
+    }
+
+    void insert(const string& s) {
+        int p = 0;
+        for (char c : s) {
+            int d = c - 'a';
+            if (!t[p][d]) t[p][d] = sz++;
+            p = t[p][d];
+        }
+        cnt[p]++;
+    }
+
+    void build() {
+        queue<int> q;
+        for (int i = 0; i < 26; i++) {
+            if (t[0][i]) q.push(t[0][i]);
+        }
+        while (!q.empty()) {
+            int u = q.front();
+            q.pop();
+            for (int i = 0; i < 26; i++) {
+                int& v = t[u][i];
+                if (v) {
+                    fail[v] = t[fail[u]][i];
+                    nxt[v] = cnt[fail[v]] ? fail[v] : nxt[fail[v]];
+                    q.push(v);
+                } else {
+                    v = t[fail[u]][i];
+                }
+            }
+        }
+    }
+};
+```
+
+### suffix automaton
+
+```cpp
+// 1-indexed
+// the array a in rsort is the topological order [1, sz)
+struct SAM {
+    static constexpr int M = N << 1;
+    int t[M][26], len[M], fa[M], sz = 2, last = 1;
+    void init() {
+        memset(t, 0, (sz + 2) * sizeof t[0]);
+        sz = 2;
+        last = 1;
+    }
+    void ins(int ch) {
+        int p = last, np = last = sz++;
+        len[np] = len[p] + 1;
+        for (; p && !t[p][ch]; p = fa[p]) t[p][ch] = np;
+        if (!p) {
+            fa[np] = 1;
+            return;
+        }
+        int q = t[p][ch];
+        if (len[q] == len[p] + 1) {
+            fa[np] = q;
+        } else {
+            int nq = sz++;
+            len[nq] = len[p] + 1;
+            memcpy(t[nq], t[q], sizeof t[0]);
+            fa[nq] = fa[q];
+            fa[np] = fa[q] = nq;
+            for (; t[p][ch] == q; p = fa[p]) t[p][ch] = nq;
+        }
+    }
+
+    int c[M] = {1}, a[M];
+    void rsort() {
+        for (int i = 1; i < sz; ++i) c[i] = 0;
+        for (int i = 1; i < sz; ++i) c[len[i]]++;
+        for (int i = 1; i < sz; ++i) c[i] += c[i - 1];
+        for (int i = 1; i < sz; ++i) a[--c[len[i]]] = i;
+    }
+};
+```
+
++ suffix automaton (multiple strings, on-line construction)
+
+```cpp
+// set last = 1 before inserting new string
+struct SAM {
+    static constexpr int M = N << 1;
+    int t[M][26], len[M], fa[M], sz = 2, last = 1;
+    void init() {
+        memset(t, 0, (sz + 2) * sizeof t[0]);
+        sz = 2;
+        last = 1;
+    }
+    void ins(int ch) {
+        int p = last, np = 0, nq = 0, q = -1;
+        if (!t[p][ch]) {
+            np = sz++;
+            len[np] = len[p] + 1;
+            for (; p && !t[p][ch]; p = fa[p]) t[p][ch] = np;
+        }
+        if (!p) {
+            fa[np] = 1;
+        } else {
+            q = t[p][ch];
+            if (len[p] + 1 == len[q]) {
+                fa[np] = q;
+            } else {
+                nq = sz++;
+                len[nq] = len[p] + 1;
+                memcpy(t[nq], t[q], sizeof t[0]);
+                fa[nq] = fa[q];
+                fa[np] = fa[q] = nq;
+                for (; t[p][ch] == q; p = fa[p]) t[p][ch] = nq;
+            }
+        }
+        last = np ? np : nq ? nq : q;
+    }
+};
+```
+
+### suffix arrays
+
+```cpp
+// 1-indexed
+// sa[i]: position of the suffix with rank i
+// rk[i]: rank of the i-th suffix
+// ht[i]: LCP(sa[i], sa[i - 1])
+struct SA {
+    int n, m;
+    vector<int> a, d, sa, rk, ht;
+
+    void rsort() {
+        vector<int> c(m + 1);
+        for (int i = 1; i <= n; i++) c[rk[d[i]]]++;
+        for (int i = 1; i <= m; i++) c[i] += c[i - 1];
+        for (int i = n; i; i--) sa[c[rk[d[i]]]--] = d[i];
+    }
+
+    SA(const string& s) : n(s.size()), m(128), a(n + 1), d(n + 1), sa(n + 1), rk(n + 1), ht(n + 1) {
+        for (int i = 1; i <= n; i++) { rk[i] = a[i] = s[i - 1]; d[i] = i; }
+        rsort();
+        for (int j = 1, i, k; k < n; m = k, j <<= 1) {
+            for (i = n - j + 1, k = 0; i <= n; i++) d[++k] = i;
+            for (i = 1; i <= n; i++) if (sa[i] > j) d[++k] = sa[i] - j;
+            rsort(); swap(rk, d); rk[sa[1]] = k = 1;
+            for (i = 2; i <= n; i++) {
+                rk[sa[i]] = (d[sa[i]] == d[sa[i - 1]] && d[sa[i] + j] == d[sa[i - 1] + j]) ? k : ++k;
+            }
+        }
+        int j, k = 0;
+        for (int i = 1; i <= n; ht[rk[i++]] = k) {
+            for (k ? k-- : k, j = sa[rk[i] - 1]; a[i + k] == a[j + k]; ++k);
+        }
+    }
+};
+```
diff --git a/4-Math.md b/4-Math.md
new file mode 100644
index 0000000..eb8b899
--- /dev/null
+++ b/4-Math.md
@@ -0,0 +1,1015 @@
+## Math
+
+### GCD & LCM
+
+```cpp
+ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
+ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }
+```
+
+### safe multiply & fast power
+
+```cpp
+// use if modulo > INT_MAX
+ll mul(ll a, ll b, ll p) {
+    ll ans = 0;
+    for (a %= p; b; b >>= 1, a = (a << 1) % p)
+        if (b & 1) ans = (ans + a) % p;
+    return ans;
+}
+
+// O(1)
+ll mul(ll a, ll b, ll p) {
+    return (ll)(__int128(a) * b % p);
+}
+
+ll qk(ll a, ll b, ll p) {
+    ll ans = 1 % p;
+    for (a %= p; b; b >>= 1, a = a * a % p)
+        if (b & 1) ans = ans * a % p;
+    return ans;
+}
+
+// if modulo > INT_MAX
+ll qk(ll a, ll b, ll p) {
+    ll ans = 1 % p;
+    for (a %= p; b; b >>= 1, a = mul(a, a, p))
+        if (b & 1) ans = mul(ans, a, p);
+    return ans;
+}
+
+// decimal fast power
+ll qk(ll a, const string& b, ll p) {
+    ll ans = 1;
+    for (int i = b.size() - 1; i >= 0; i--) {
+        ans = ans * qk(a, b[i] - '0', p) % p;
+        a = qk(a, 10, p);
+    }
+    return ans;
+}
+```
+
+### matrix power
+
+```cpp
+const int M_SZ = 3;
+
+using Mat = array<array<ll, M_SZ>, M_SZ>;
+
+#define rep2 for (int i = 0; i < M_SZ; i++) for (int j = 0; j < M_SZ; j++)
+
+void zero(Mat& a) { rep2 a[i][j] = 0; }
+void one(Mat& a) { rep2 a[i][j] = (i == j); }
+
+Mat mul(const Mat& a, const Mat& b, ll p) {
+    Mat ans; zero(ans);
+    rep2 if (a[i][j]) for (int k = 0; k < M_SZ; k++) {
+        (ans[i][k] += a[i][j] * b[j][k]) %= p;
+    }
+    return ans;
+}
+
+Mat qk(Mat a, ll b, ll p) {
+    Mat ans; one(ans);
+    for (; b; b >>= 1) {
+        if (b & 1) ans = mul(a, ans, p);
+        a = mul(a, a, p);
+    }
+    return ans;
+}
+
+// decimal fast power
+Mat qk(Mat a, const string& b, ll p) {
+    Mat ans; one(ans);
+    for (int i = b.size() - 1; i >= 0; i--) {
+        ans = mul(qk(a, b[i] - '0', p), ans, p);
+        a = qk(a, 10, p);
+    }
+    return ans;
+}
+
+#undef rep2
+```
+
+### prime test
+
+```cpp
+bool isprime(int x) {
+    if (x < 2) return false;
+    for (int i = 2; i * i <= x; i++) {
+        if (x % i == 0) return false;
+    }
+    return true;
+}
+```
+
+### linear sieve
+
+```cpp
+// Note: 0 and 1 are not prime numbers
+bool vis[N];
+int prime[N];
+
+void get_prime() {
+    int tot = 0;
+    for (int i = 2; i < N; i++) {
+        if (!vis[i]) prime[tot++] = i;
+        for (int j = 0; j < tot; j++) {
+            int d = i * prime[j];
+            if (d >= N) break;
+            vis[d] = true;
+            if (i % prime[j] == 0) break;
+        }
+    }
+}
+
+// smallest prime factor
+bool vis[N];
+int spf[N], prime[N];
+
+void get_spf() {
+    int tot = 0;
+    for (int i = 2; i < N; i++) {
+        if (!vis[i]) {
+            prime[tot++] = i;
+            spf[i] = i;
+        }
+        for (int j = 0; j < tot; j++) {
+            int d = i * prime[j];
+            if (d >= N) break;
+            vis[d] = true;
+            spf[d] = prime[j];
+            if (i % prime[j] == 0) break;
+        }
+    }
+}
+
+// Euler's phi function
+bool vis[N];
+int phi[N], prime[N];
+
+void get_phi() {
+    int tot = 0;
+    phi[1] = 1;
+    for (int i = 2; i < N; i++) {
+        if (!vis[i]) {
+            prime[tot++] = i;
+            phi[i] = i - 1;
+        }
+        for (int j = 0; j < tot; j++) {
+            int d = i * prime[j];
+            if (d >= N) break;
+            vis[d] = true;
+            if (i % prime[j] == 0) {
+                phi[d] = phi[i] * prime[j];
+                break;
+            }
+            else phi[d] = phi[i] * (prime[j] - 1);
+        }
+    }
+}
+
+// Möbius function
+bool vis[N];
+int mu[N], prime[N];
+
+void get_mu() {
+    int tot = 0;
+    mu[1] = 1;
+    for (int i = 2; i < N; i++) {
+        if (!vis[i]) {
+            prime[tot++] = i;
+            mu[i] = -1;
+        }
+        for (int j = 0; j < tot; j++) {
+            int d = i * prime[j];
+            if (d >= N) break;
+            vis[d] = true;
+            if (i % prime[j] == 0) {
+                mu[d] = 0;
+                break;
+            }
+            else mu[d] = -mu[i];
+        }
+    }
+}
+```
+
+### interval sieve
+
+```cpp
+// a, b <= 1e13, b - a <= 1e6
+bool vis_small[N], vis_big[N];
+ll prime[N];
+int tot = 0;
+
+void get_prime(ll a, ll b) {
+    ll c = ceil(sqrt(b));
+    for (ll i = 2; i <= c; i++) {
+        if (!vis_small[i]) {
+            for (ll j = i * i; j <= c; j += i) {
+                vis_small[j] = 1;
+            }
+            for (ll j = max(i, (a + i - 1) / i) * i; j <= b; j += i) {
+                vis_big[j - a] = 1;
+            }
+        }
+    }
+    for (int i = max(0LL, 2 - a); i <= b - a; i++) {
+        if (!vis_big[i]) prime[tot++] = i + a;
+    }
+}
+```
+
+### find factors
+
+```cpp
+// O(sqrt(n))
+vector<int> getf(int x) {
+    vector<int> v;
+    for (int i = 1; i * i <= x; i++) {
+        if (x % i == 0) {
+            v.push_back(i);
+            if (x / i != i) v.push_back(x / i);
+        }
+    }
+    sort(v.begin(), v.end());
+    return v;
+}
+```
+
+### find prime factors
+
+```cpp
+// O(sqrt(n)), no duplicates
+vector<int> getf(int x) {
+    vector<int> v;
+    for (int i = 2; i * i <= x; i++) {
+        if (x % i == 0) {
+            v.push_back(i);
+            while (x % i == 0) x /= i;
+        }
+    }
+    if (x != 1) v.push_back(x);
+    return v;
+}
+
+// O(sqrt(n)), with duplicates
+vector<int> getf(int x) {
+    vector<int> v;
+    for (int i = 2; i * i <= x; i++) {
+        while (x % i == 0) {
+            v.push_back(i);
+            x /= i;
+        }
+    }
+    if (x != 1) v.push_back(x);
+    return v;
+}
+
+// prerequisite: linear sieve
+// O(logn), no duplicates
+vector<int> getf(int x) {
+    vector<int> v;
+    while (x > 1) {
+        int p = spf[x];
+        v.push_back(p);
+        while (x % p == 0) x /= p;
+    }
+    return v;
+}
+
+// O(logn), with duplicates
+vector<int> getf(int x) {
+    vector<int> v;
+    while (x > 1) {
+        int p = spf[x];
+        while (x % p == 0) {
+            v.push_back(p);
+            x /= p;
+        }
+    }
+    return v;
+}
+```
+
+### Miller & Pollard
+
+```cpp
+ll mul(ll a, ll b, ll p) { return (ll)(__int128(a) * b % p); }
+
+ll qk(ll a, ll b, ll p) {
+    ll ans = 1 % p;
+    for (a %= p; b; b >>= 1, a = mul(a, a, p))
+        if (b & 1) ans = mul(ans, a, p);
+    return ans;
+}
+
+// O(logn)
+// only need to check 2, 7, 61 for 32-bit int
+bool isprime(ll n) {
+    if (n < 3) return n == 2;
+    if (!(n & 1)) return false;
+    ll d = n - 1, r = 0;
+    while (!(d & 1)) d >>= 1, r++;
+    static vector<ll> A = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
+    for (ll a : A) {
+        ll t = qk(a, d, n);
+        if (t <= 1 || t == n - 1) continue;
+        for (int i = 0; i < r; i++) {
+            t = mul(t, t, n);
+            if (t == 1) return false;
+            if (t == n - 1) break;
+        }
+        if (t != 1 && t != n - 1) return false;
+    }
+    return true;
+}
+
+mt19937_64 rng(42);
+
+ll pollard_rho(ll n, ll c) {
+    ll x = rng() % (n - 1) + 1, y = x;
+    auto f = [&](ll v) {
+        ll t = mul(v, v, n) + c;
+        return t < n ? t : t - n;
+    };
+    for (;;) {
+        x = f(x); y = f(f(y));
+        if (x == y) return n;
+        ll d = gcd(abs(x - y), n);
+        if (d != 1) return d;
+    }
+}
+
+vector<ll> getf(ll x) {
+    vector<ll> v;
+    if (x <= 1) return v;
+    function<void(ll)> f = [&](ll n) {
+        if (n == 4) { v.push_back(2); v.push_back(2); return; }
+        if (isprime(n)) { v.push_back(n); return; }
+        ll p = n, c = 19260817;
+        while (p == n) p = pollard_rho(n, --c);
+        f(p); f(n / p);
+    };
+    f(x);
+    return v;
+}
+```
+
+### Euler's phi function
+
+```cpp
+// prerequisite: find prime factors (no duplicates)
+int phi(int x) {
+    int ret = x;
+    vector<int> v = getf(x);
+    for (int f : v) ret = ret / f * (f - 1);
+    return ret;
+}
+
+// O(nloglogn)
+int phi[N];
+
+void get_phi() {
+    phi[1] = 1;
+    for (int i = 2; i < N; i++) {
+        if (!phi[i]) {
+            for (int j = i; j < N; j += i) {
+                if (!phi[j]) phi[j] = j;
+                phi[j] = phi[j] / i * (i - 1);
+            }
+        }
+    }
+}
+```
+
+### extended Euclidean (aka EXGCD)
+
+```cpp
+// ax + by = gcd(a, b)
+ll exgcd(ll a, ll b, ll &x, ll &y) {
+    if (b == 0) {
+        x = 1;
+        y = 0;
+        return a;
+    }
+    ll d = exgcd(b, a % b, y, x);
+    y -= a / b * x;
+    return d;
+}
+```
+
+### Euclidean-like algorithm
+
+```cpp
+// f(a,b,c,n) = ∑(i=[0,n]) (ai+b)/c
+// g(a,b,c,n) = ∑(i=[0,n]) i*((ai+b)/c)
+// h(a,b,c,n) = ∑(i=[0,n]) ((ai+b)/c)^2
+ll f(ll a, ll b, ll c, ll n);
+ll g(ll a, ll b, ll c, ll n);
+ll h(ll a, ll b, ll c, ll n);
+
+ll f(ll a, ll b, ll c, ll n) {
+    if (n < 0) return 0;
+    ll m = (a * n + b) / c;
+    if (a >= c || b >= c) {
+        return (a / c) * n * (n + 1) / 2
+        + (b / c) * (n + 1)
+        + f(a % c, b % c, c, n);
+    } else {
+        return n * m - f(c, c - b - 1, a, m - 1);
+    }
+}
+
+ll g(ll a, ll b, ll c, ll n) {
+    if (n < 0) return 0;
+    ll m = (a * n + b) / c;
+    if (a >= c || b >= c) {
+        return (a / c) * n * (n + 1) * (2 * n + 1) / 6
+        + (b / c) * n * (n + 1) / 2
+        + g(a % c, b % c, c, n);
+    } else {
+        return (n * (n + 1) * m
+        - f(c, c - b - 1, a, m - 1) 
+        - h(c, c - b - 1, a, m - 1)) / 2;
+    }
+}
+
+ll h(ll a, ll b, ll c, ll n) {
+    if (n < 0) return 0;
+    ll m = (a * n + b) / c;
+    if (a >= c || b >= c) {
+        return (a / c) * (a / c) * n * (n + 1) * (2 * n + 1) / 6
+        + (b / c) * (b / c) * (n + 1)
+        + (a / c) * (b / c) * n * (n + 1)
+        + h(a % c, b % c, c, n)
+        + 2 * (a / c) * g(a % c, b % c, c, n)
+        + 2 * (b / c) * f(a % c, b % c, c, n);
+    } else {
+        return n * m * (m + 1)
+        - 2 * g(c, c - b - 1, a, m - 1)
+        - 2 * f(c, c - b - 1, a, m - 1)
+        - f(a, b, c, n);
+    }
+}
+```
+
+### modular multiplicative inverse
+
+```cpp
+ll inv(ll x) { return qk(x, MOD - 2, MOD); }
+
+// EXGCD
+// exists iff gcd(a, p) = 1
+ll inv(ll a, ll p) {
+    ll x, y;
+    ll d = exgcd(a, p, x, y);
+    if (d == 1) return (x % p + p) % p;
+    return -1;
+}
+
+// inverse table
+ll inv[N];
+
+void init_inv() {
+    inv[1] = 1;
+    for (int i = 2; i < N; i++) {
+        inv[i] = 1LL * (MOD - MOD / i) * inv[MOD % i] % MOD;
+    }
+}
+```
+
+### binomial coefficient
+
+```cpp
+// binomial coefficient table
+ll C[N][N];
+
+void initC() {
+    C[0][0] = 1;
+    for (int i = 1; i < N; i++) {
+        C[i][0] = 1;
+        for (int j = 1; j <= i; j++) {
+            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
+        }
+    }
+}
+
+// fast binomial coefficient modulo
+// N needs to be 2x
+ll fac[N], ifac[N];
+
+void init_inv() {
+    fac[0] = 1;
+    for (int i = 1; i < N; i++) {
+        fac[i] = fac[i - 1] * i % MOD;
+    }
+    ifac[N - 1] = qk(fac[N - 1], MOD - 2, MOD);
+    for (int i = N - 2; i >= 0; i--) {
+        ifac[i] = ifac[i + 1] * (i + 1) % MOD;
+    }
+}
+
+ll C(int n, int m) {
+    if (n < m || m < 0) return 0;
+    return fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;
+}
+
+// Lucas
+ll C(ll n, ll m) {
+    if (n < m || m < 0) return 0;
+    if (n < MOD && m < MOD) return fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;
+    return C(n / MOD, m / MOD) * C(n % MOD, m % MOD) % MOD;
+}
+
+// combination with repetition
+ll H(int n, int m) { return C(n + m - 1, m); }
+```
+
+### Cantor expansion
+
+```cpp
+// prerequisite: factorial table
+int cantor(vector<int>& s) {
+    int n = s.size(), ans = 0;
+    for (int i = 0; i < n - 1; i++) {
+        int cnt = 0;
+        for (int j = i + 1; j < n; j++) {
+            if (s[j] < s[i]) cnt++;
+        }
+        ans += cnt * fac[n - i - 1];
+    }
+    return ans + 1;
+}
+
+vector<int> inv_cantor(int x, int n) {
+    x--;
+    vector<int> ans(n), rk(n);
+    iota(rk.begin(), rk.end(), 1);
+    for (int i = 0; i < n; i++) {
+        int t = x / fac[n - i - 1];
+        x %= fac[n - i - 1];
+        ans[i] = rk[t];
+        for (int j = t; rk[j] < n; j++) {
+            rk[j] = rk[j + 1];
+        }
+    }
+    return ans;
+}
+```
+
+### Gauss-Jordan elimination
+
+```cpp
+// n equations, m variables, a is an augmented matrix of n*(m+1), free is a free variable or not
+// return the number of free variables, -1 if no solution
+const double EPS = 1e-8;
+const int N = 500 + 7;
+
+double x[N];
+bool free_x[N];
+
+int sgn(double x) { return x < -EPS ? -1 : x > EPS; }
+
+int gauss(vector<vector<double> >& a, int n, int m) {
+    fill(x, x + m + 1, 0);
+    fill(free_x, free_x + m + 1, true);
+
+    // find the upper triangular matrix
+    int r = 0, c = 0;
+    while (r < n && c < m) {
+        int mr = r;
+        for (int i = r + 1; i < n; i++) {
+            if (abs(a[i][c]) > abs(a[mr][c])) mr = i;
+        }
+        if (mr != r) swap(a[r], a[mr]);
+        if (!sgn(a[r][c])) {
+            a[r][c] = 0;
+            ++c;
+            continue;
+        }
+        for (int i = r + 1; i < n; i++) {
+            if (a[i][c]) {
+                double t = a[i][c] / a[r][c];
+                for (int j = c; j <= m; j++) a[i][j] -= a[r][j] * t;
+            }
+        }
+        ++r, ++c;
+    }
+    for (int i = r; i < n; i++) {
+        if (sgn(a[i][m])) return -1;
+    }
+
+    // solve x0, x1, ..., xm-1
+    if (r < m) {
+        for (int i = r - 1; i >= 0; i--) {
+            int fcnt = 0, k = -1;
+            for (int j = 0; j < m; j++) {
+                if (sgn(a[i][j]) && free_x[j]) {
+                    ++fcnt;
+                    k = j;
+                }
+            }
+            if (fcnt > 0) continue;
+            double s = a[i][m];
+            for (int j = 0; j < m; j++) {
+                if (j != k) s -= a[i][j] * x[j];
+            }
+            x[k] = s / a[i][k];
+            free_x[k] = 0;
+        }
+        return m - r;
+    }
+    for (int i = m - 1; i >= 0; i--) {
+        double s = a[i][m];
+        for (int j = i + 1; j < m; j++) s -= a[i][j] * x[j];
+        x[i] = s / a[i][i];
+    }
+    return 0;
+}
+```
+
+### linear basis
+
+```cpp
+struct Basis {
+    vector<ll> a;
+    void insert(ll x) {
+        x = minxor(x);
+        if (!x) return;
+        for (ll& i : a)
+            if ((i ^ x) < i) i ^= x;
+        a.push_back(x);
+        sort(a.begin(), a.end());
+    }
+    bool can(ll x) { return !minxor(x); }
+    ll maxxor(ll x = 0) {
+        for (ll i : a) x = max(x, x ^ i);
+        return x;
+    }
+    ll minxor(ll x = 0) {
+        for (ll i : a) x = min(x, x ^ i);
+        return x;
+    }
+    ll kth(ll k) {  // 1st is 0
+        int sz = a.size();
+        if (k > (1LL << sz)) return -1;
+        k--;
+        ll ans = 0;
+        for (int i = 0; i < sz; i++)
+            if (k >> i & 1) ans ^= a[i];
+        return ans;
+    }
+};
+```
+
+### Chinese remainder theorem
+
+```cpp
+// prerequisite: exgcd
+ll excrt(vector<ll>& m, vector<ll>& r) {
+    ll M = m[0], R = r[0], x, y, d;
+    for (int i = 1; i < m.size(); i++) {
+        d = exgcd(M, m[i], x, y);
+        if ((r[i] - R) % d) return -1;
+        x = mul(x, (r[i] - R) / d, m[i] / d);
+        R += x * M;
+        M = M / d * m[i];
+        R %= M;
+    }
+    return R >= 0 ? R : R + M;
+}
+```
+
+### primitive root
+
+```cpp
+// prerequisite: find prime factors (no duplicates)
+ll primitive_root(ll p) {
+    vector<ll> facs = getf(p - 1);
+    for (ll i = 2; i < p; i++) {
+        bool flag = true;
+        for (ll x : facs) {
+            if (qk(i, (p - 1) / x, p) == 1) {
+                flag = false;
+                break;
+            }
+        }
+        if (flag) return i;
+    }
+    return -1;
+}
+```
+
+### BSGS
+
+```cpp
+// a ^ x = b (mod p),require prime modulus
+ll BSGS(ll a, ll b, ll p) {
+    a %= p;
+    if (!a && !b) return 1;
+    if (!a) return -1;
+    map<ll, ll> mp;
+    ll m = ceil(sqrt(p)), v = 1;
+    for (int i = 1; i <= m; i++) {
+        (v *= a) %= p;
+        mp[v * b % p] = i;
+    }
+    ll vv = v;
+    for (int i = 1; i <= m; i++) {
+        auto it = mp.find(vv);
+        if (it != mp.end()) return i * m - it->second;
+        (vv *= v) %= p;
+    }
+    return -1;
+}
+
+// modulus can be non-prime
+ll exBSGS(ll a, ll b, ll p) {
+    a %= p; b %= p;
+    if (a == 0) return b > 1 ? -1 : (b == 0 && p != 1);
+    ll c = 0, q = 1;
+    for (;;) {
+        ll g = gcd(a, p);
+        if (g == 1) break;
+        if (b == 1) return c;
+        if (b % g) return -1;
+        ++c; b /= g; p /= g; q = a / g * q % p;
+    }
+    map<ll, ll> mp;
+    ll m = ceil(sqrt(p)), v = 1;
+    for (int i = 1; i <= m; i++) {
+        (v *= a) %= p;
+        mp[v * b % p] = i;
+    }
+    for (int i = 1; i <= m; i++) {
+        (q *= v) %= p;
+        auto it = mp.find(q);
+        if (it != mp.end()) return i * m - it->second + c;
+    }
+    return -1;
+}
+
+// given x, b, p, find a
+ll SGSB(ll x, ll b, ll p) {
+    ll g = primitive_root(p);
+    return qk(g, BSGS(qk(g, x, p), b, p), p);
+}
+```
+
+### quadratic residue
+
+```cpp
+ll Quadratic_residue(ll a) {
+    if (a == 0) return 0;
+    ll b;
+    do b = rng() % MOD;
+    while (qk(b, (MOD - 1) >> 1, MOD) != MOD - 1);
+    ll s = MOD - 1, t = 0, f = 1;
+    while (!(s & 1)) s >>= 1, t++, f <<= 1;
+    t--, f >>= 1;
+    ll x = qk(a, (s + 1) >> 1, MOD), inv_a = qk(a, MOD - 2, MOD);
+    while (t) {
+        f >>= 1;
+        if (qk(inv_a * x % MOD * x % MOD, f, MOD) != 1) {
+            (x *= qk(b, s, MOD)) %= MOD;
+        }
+        t--, s <<= 1;
+    }
+    if (x * x % MOD != a) return -1;
+    return min(x, MOD - x);
+}
+```
+
+### FFT & NTT & FWT
+
++ FFT
+
+```cpp
+const double PI = acos(-1);
+using cp = complex<double>;
+
+int n1, n2, n, k, rev[N];
+
+void fft(vector<cp>& a, int p) {
+    for (int i = 0; i < n; i++) if (i < rev[i]) swap(a[i], a[rev[i]]);
+    for (int h = 1; h < n; h <<= 1) {
+        cp wn(cos(PI / h), p * sin(PI / h));
+        for (int i = 0; i < n; i += (h << 1)) {
+            cp w(1, 0);
+            for (int j = 0; j < h; j++, w *= wn) {
+                cp x = a[i + j], y = w * a[i + j + h];
+                a[i + j] = x + y, a[i + j + h] = x - y;
+            }
+        }
+    }
+    if (p == -1) for (int i = 0; i < n; i++) a[i] /= n;
+}
+
+void go(vector<cp>& a, vector<cp>& b) {
+    n = 1, k = 0;
+    while (n <= n1 + n2) n <<= 1, k++;
+    a.resize(n); b.resize(n);
+    for (int i = 0; i < n; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
+    fft(a, 1); fft(b, 1);
+    for (int i = 0; i < n; i++) a[i] *= b[i];
+    fft(a, -1);
+}
+```
+
++ NTT
+
+```cpp
+const int MOD = 998244353, G = 3, IG = 332748118;
+
+int n1, n2, n, k, rev[N];
+
+void ntt(vector<ll>& a, int p) {
+    for (int i = 0; i < n; i++) if (i < rev[i]) swap(a[i], a[rev[i]]);
+    for (int h = 1; h < n; h <<= 1) {
+        ll wn = qk(p == 1 ? G : IG, (MOD - 1) / (h << 1), MOD);
+        for (int i = 0; i < n; i += (h << 1)) {
+            ll w = 1;
+            for (int j = 0; j < h; j++, (w *= wn) %= MOD) {
+                ll x = a[i + j], y = w * a[i + j + h] % MOD;
+                a[i + j] = (x + y) % MOD, a[i + j + h] = (x - y + MOD) % MOD;
+            }
+        }
+    }
+    if (p == -1) {
+        ll ninv = qk(n, MOD - 2, MOD);
+        for (int i = 0; i < n; i++) (a[i] *= ninv) %= MOD;
+    }
+}
+
+void go(vector<ll>& a, vector<ll>& b) {
+    n = 1, k = 0;
+    while (n <= n1 + n2) n <<= 1, k++;
+    a.resize(n); b.resize(n);
+    for (int i = 0; i < n; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
+    ntt(a, 1); ntt(b, 1);
+    for (int i = 0; i < n; i++) (a[i] *= b[i]) %= MOD;
+    ntt(a, -1);
+}
+```
+
++ FWT
+
+```cpp
+void AND(ll& a, ll& b) { a += b; }
+void rAND(ll& a, ll& b) { a -= b; }
+
+void OR(ll& a, ll& b) { b += a; }
+void rOR(ll& a, ll& b) { b -= a; }
+
+void XOR(ll& a, ll& b) {
+    ll x = a, y = b;
+    a = (x + y) % MOD;
+    b = (x - y + MOD) % MOD;
+}
+void rXOR(ll& a, ll& b) {
+    static ll inv2 = (MOD + 1) / 2;
+    ll x = a, y = b;
+    a = (x + y) * inv2 % MOD;
+    b = (x - y + MOD) * inv2 % MOD;
+}
+
+template<class T>
+void fwt(vector<ll>& a, int n, T f) {
+    for (int d = 1; d < n; d <<= 1) {
+        for (int i = 0; i < n; i += (d << 1)) {
+            for (int j = 0; j < d; j++) {
+                f(a[i + j], a[i + j + d]);
+            }
+        }
+    }
+}
+```
+
+### adaptive Simpson's method
+
+```cpp
+double simpson(double l, double r) {
+    double c = (l + r) / 2;
+    return (f(l) + 4 * f(c) + f(r)) * (r - l) / 6;
+}
+
+double asr(double l, double r, double eps, double S) {
+    double mid = (l + r) / 2;
+    double L = simpson(l, mid), R = simpson(mid, r);
+    if (fabs(L + R - S) < 15 * eps) return L + R + (L + R - S) / 15;
+    return asr(l, mid, eps / 2, L) + asr(mid, r, eps / 2, R);
+}
+
+double asr(double l, double r) { return asr(l, r, EPS, simpson(l, r)); }
+```
+
+### Berlekamp–Massey linear recurrence
+
+```cpp
+namespace BerlekampMassey {
+    using V = vector<ll>;
+
+    void up(ll & a, ll b) { (a += b) %= MOD; }
+
+    V mul(const V& a, const V& b, const V& m, int k) {
+        V r(2 * k - 1);
+        for (int i = 0; i < k; i++)
+            for (int j = 0; j < k; j++)
+                up(r[i + j], a[i] * b[j]);
+        for (int i = k - 2; i >= 0; i--) {
+            for (int j = 0; j < k; j++)
+                up(r[i + j], r[i + k] * m[j]);
+            r.pop_back();
+        }
+        return r;
+    }
+
+    V pow(ll n, const V& m) {
+        int k = (int)m.size() - 1;
+        assert(m[k] == -1 || m[k] == MOD - 1);
+        V r(k), x(k);
+        r[0] = x[1] = 1;
+        for (; n; n >>= 1, x = mul(x, x, m, k))
+            if (n & 1) r = mul(x, r, m, k);
+        return r;
+    }
+
+    ll go(const V& a, const V& x, ll n) {
+        // a: (-1, a1, a2, ..., ak).reverse
+        // x: x1, x2, ..., xk
+        // x[n] = sum[a[i]*x[n-i],{i,1,k}]
+        int k = (int)a.size() - 1;
+        if (n <= k) return x[n - 1];
+        if (a.size() == 2) return x[0] * qk(a[0], n - 1, MOD) % MOD;
+        V r = pow(n - 1, a);
+        ll ans = 0;
+        for (int i = 0; i < k; i++) up(ans, r[i] * x[i]);
+        return (ans + MOD) % MOD;
+    }
+
+    V BM(const V& x) {
+        V C{-1}, B{-1};
+        ll L = 0, m = 1, b = 1;
+        for (int n = 0; n < (int)x.size(); n++) {
+            ll d = 0;
+            for (int i = 0; i <= L; i++) up(d, C[i] * x[n - i]);
+            if (d == 0) { ++m; continue; }
+            V T = C;
+            ll c = MOD - d * inv(b, MOD) % MOD;
+            C.resize(max(C.size(), size_t(B.size() + m)));
+            for (int i = 0; i < (int)B.size(); i++) up(C[i + m], c * B[i]);
+            if (2 * L > n) { ++m; continue; }
+            L = n + 1 - L; B.swap(T); b = d; m = 1;
+        }
+        reverse(C.begin(), C.end());
+        return C;
+    }
+}
+```
+
+### Lagrange interpolation
+
+```cpp
+// find the value of f(k), O(n^2)
+ll La(const vector<pair<ll, ll> >& v, ll k) {
+    ll ret = 0;
+    for (int i = 0; i < v.size(); i++) {
+        ll up = v[i].second % MOD, down = 1;
+        for (int j = 0; j < v.size(); j++) {
+            if (i != j) {
+                (up *= (k - v[j].first) % MOD) %= MOD;
+                (down *= (v[i].first - v[j].first) % MOD) %= MOD;
+            }
+        }
+        if (up < 0) up += MOD;
+        if (down < 0) down += MOD;
+        (ret += up * inv(down) % MOD) %= MOD;
+    }
+    return ret;
+}
+
+// find the coefficients of f(x), O(n * 2^n)
+vector<double> La(vector<pair<double, double> > v) {
+    int n = v.size(), t;
+    vector<double> ret(n);
+    double p, q;
+    for (int i = 0; i < n; i++) {
+        p = v[i].second;
+        for (int j = 0; j < n; j++) {
+            p /= (i == j) ? 1 : (v[i].first - v[j].first);
+        }
+        for (int j = 0; j < (1 << n); j++) {
+            q = 1, t = 0;
+            for (int k = 0; k < n; k++) {
+                if (i == k) continue;
+                if ((j >> k) & 1) q *= -v[k].first;
+                else t++;
+            }
+            ret[t] += p * q / 2;
+        }
+    }
+    return ret;
+}
+```
diff --git a/5-Geometry.md b/5-Geometry.md
new file mode 100644
index 0000000..c7b39c1
--- /dev/null
+++ b/5-Geometry.md
@@ -0,0 +1,315 @@
+## Computational Geometry
+
+### 2D geometry basics
+
+```cpp
+#define y1 qwq
+
+using ld = double;
+
+const ld PI = acos(-1);
+const ld EPS = 1e-8;
+
+int sgn(ld x) { return x < -EPS ? -1 : x > EPS; }
+
+// don't use sgn directly
+bool eq(ld x, ld y) { return sgn(x - y) == 0; }
+bool neq(ld x, ld y) { return sgn(x - y) != 0; }
+bool lt(ld x, ld y) { return sgn(x - y) < 0; }
+bool gt(ld x, ld y) { return sgn(x - y) > 0; }
+bool leq(ld x, ld y) { return sgn(x - y) <= 0; }
+bool geq(ld x, ld y) { return sgn(x - y) >= 0; }
+
+struct V {
+    ld x, y;
+    constexpr V(ld x = 0, ld y = 0) : x(x), y(y) {}
+    constexpr V(const V& a, const V& b) : x(b.x - a.x), y(b.y - a.y) {}
+    V operator+(const V& b) const { return V(x + b.x, y + b.y); }
+    V operator-(const V& b) const { return V(x - b.x, y - b.y); }
+    V operator*(ld k) const { return V(x * k, y * k); }
+    V operator/(ld k) const { return V(x / k, y / k); }
+    ld len() const { return hypot(x, y); }
+    ld len2() const { return x * x + y * y; }
+};
+
+ostream& operator<<(ostream& os, const V& p) { return os << "(" << p.x << ", " << p.y << ")"; }
+istream& operator>>(istream& is, V& p) { return is >> p.x >> p.y; }
+
+ld dist(const V& a, const V& b) { return (b - a).len(); }
+ld dot(const V& a, const V& b) { return a.x * b.x + a.y * b.y; }
+ld det(const V& a, const V& b) { return a.x * b.y - a.y * b.x; }
+ld cross(const V& s, const V& t, const V& o) { return det(V(o, s), V(o, t)); }
+
+ld to_rad(ld deg) { return deg / 180 * PI; }
+
+// quadrant
+int quad(const V& p) {
+    int x = sgn(p.x), y = sgn(p.y);
+    if (x > 0 && y >= 0) return 1;
+    if (x <= 0 && y > 0) return 2;
+    if (x < 0 && y <= 0) return 3;
+    if (x >= 0 && y < 0) return 4;
+    assert(0);
+}
+
+// sorting by polar angle
+struct cmp_angle {
+    V p;
+    cmp_angle(const V& p = V()) : p(p) {}
+    bool operator () (const V& a, const V& b) const {
+        int qa = quad(a - p), qb = quad(b - p);
+        if (qa != qb) return qa < qb;
+        int d = sgn(cross(a, b, p));
+        if (d) return d > 0;
+        return dist(a, p) < dist(b, p);
+    }
+};
+
+// unit vector
+V unit(const V& p) { return eq(p.len(), 0) ? V(1, 0) : p / p.len(); }
+
+// counter-clockwise rotation r radians
+V rot(const V& p, ld r) {
+    return V(p.x * cos(r) - p.y * sin(r), p.x * sin(r) + p.y * cos(r));
+}
+V rot_ccw90(const V& p) { return V(-p.y, p.x); }
+V rot_cw90(const V& p) { return V(p.y, -p.x); }
+
+// point on segment, leq(dot(...) , 0) contains endpoints, lt(dot(...) , 0) otherwise
+bool p_on_seg(const V& p, const V& a, const V& b) {
+    return eq(det(p - a, b - a), 0) && leq(dot(p - a, p - b), 0);
+}
+
+// point on ray, geq(dot(...) , 0) contains endpoints, gt(dot(...) , 0) otherwise
+bool p_on_ray(const V& p, const V& a, const V& b) {
+    return eq(det(p - a, b - a), 0) && geq(dot(p - a, b - a), 0);
+}
+
+// distance to line
+ld dist_to_line(const V& p, const V& a, const V& b) {
+    return abs(cross(a, b, p) / dist(a, b));
+}
+
+// distance to segment
+ld dist_to_seg(const V& p, const V& a, const V& b) {
+    if (lt(dot(b - a, p - a), 0)) return dist(p, a);
+    if (lt(dot(a - b, p - b), 0)) return dist(p, b);
+    return dist_to_line(p, a, b);
+}
+
+// line intersection
+V intersect(const V& a, const V& b, const V& c, const V& d) {
+    ld s1 = cross(c, d, a), s2 = cross(c, d, b);
+    return (a * s2 - b * s1) / (s2 - s1);
+}
+
+// projection point
+V proj(const V& p, const V& a, const V& b) {
+    return a + (b - a) * dot(b - a, p - a) / (b - a).len2();
+}
+
+// reflect point
+V reflect(const V& p, const V& a, const V& b) {
+    return proj(p, a, b) * 2 - p;
+}
+
+// centroid
+V centroid(const V& a, const V& b, const V& c) {
+    return (a + b + c) / 3;
+}
+
+// incenter
+V incenter(const V& a, const V& b, const V& c) {
+    ld AB = dist(a, b), AC = dist(a, c), BC = dist(b, c);
+    // ld r = abs(cross(b, c, a)) / (AB + AC + BC);
+    return (a * BC + b * AC + c * AB) / (AB + BC + AC);
+}
+
+// circumcenter
+V circumcenter(const V& a, const V& b, const V& c) {
+    V mid1 = (a + b) / 2, mid2 = (a + c) / 2;
+    // ld r = dist(a, b) * dist(b, c) * dist(c, a) / 2 / abs(cross(b, c, a));
+    return intersect(mid1, mid1 + rot_ccw90(b - a), mid2, mid2 + rot_ccw90(c - a));
+}
+
+// orthocenter
+V orthocenter(const V& a, const V& b, const V& c) {
+    return centroid(a, b, c) * 3 - circumcenter(a, b, c) * 2;
+}
+
+// escenter (3)
+vector<V> escenter(const V& a, const V& b, const V& c) {
+    ld AB = dist(a, b), AC = dist(a, c), BC = dist(b, c);
+    V p1 = (a * (-BC) + b * AC + c * AB) / (AB + AC - BC);
+    V p2 = (a * BC + b * (-AC) + c * AB) / (AB - AC + BC);
+    V p3 = (a * BC + b * AC + c * (-AB)) / (-AB + AC + BC);
+    return {p1, p2, p3};
+}
+```
+
+### polygon
+
+```cpp
+// polygon area
+ld area(const vector<V>& s) {
+    ld ret = 0;
+    for (int i = 0; i < s.size(); i++) {
+        ret += det(s[i], s[(i + 1) % s.size()]);
+    }
+    return ret / 2;
+}
+
+// polygon centroid
+V centroid(const vector<V>& s) {
+    V c;
+    for (int i = 0; i < s.size(); i++) {
+        c = c + (s[i] + s[(i + 1) % s.size()]) * det(s[i], s[(i + 1) % s.size()]);
+    }
+    return c / 6.0 / area(s);
+}
+
+// point and polygon
+// 1 inside 0 on border -1 outside
+int inside(const vector<V>& s, const V& p) {
+    int cnt = 0;
+    for (int i = 0; i < s.size(); i++) {
+        V a = s[i], b = s[(i + 1) % s.size()];
+        if (p_on_seg(p, a, b)) return 0;
+        if (leq(a.y, b.y)) swap(a, b);
+        if (gt(p.y, a.y)) continue;
+        if (leq(p.y, b.y)) continue;
+        cnt += gt(cross(b, a, p), 0);
+    }
+    return (cnt & 1) ? 1 : -1;
+}
+
+// convex hull, points cannot be duplicated
+// lt(cross(...), 0) allow point on edges leq(cross(...), 0) otherwise
+// will change the order of the input points
+vector<V> convex_hull(vector<V>& s) {
+    // assert(s.size() >= 3);
+    sort(s.begin(), s.end(), [](V &a, V &b) { return eq(a.x, b.x) ? lt(a.y, b.y) : lt(a.x, b.x); });
+    vector<V> ret(2 * s.size());
+    int sz = 0;
+    for (int i = 0; i < s.size(); i++) {
+        while (sz > 1 && leq(cross(ret[sz - 1], s[i], ret[sz - 2]), 0)) sz--;
+        ret[sz++] = s[i];
+    }
+    int k = sz;
+    for (int i = s.size() - 2; i >= 0; i--) {
+        while (sz > k && leq(cross(ret[sz - 1], s[i], ret[sz - 2]), 0)) sz--;
+        ret[sz++] = s[i];
+    }
+    ret.resize(sz - (s.size() > 1));
+    return ret;
+}
+
+// is convex?
+bool is_convex(const vector<V>& s) {
+    for (int i = 0; i < s.size(); i++) {
+        if (lt(cross(s[(i + 1) % s.size()], s[(i + 2) % s.size()], s[i]), 0)) return false;
+    }
+    return true;
+}
+
+// point and convex hull
+// 1 inside 0 on border -1 outside
+int inside(const vector<V>& s, const V& p) {
+    for (int i = 0; i < s.size(); i++) {
+        if (lt(cross(s[i], s[(i + 1) % s.size()], p), 0)) return -1;
+        if (p_on_seg(p, s[i], s[(i + 1) % s.size()])) return 0;
+    }
+    return 1;
+}
+
+// closest pair of points, sort by x-coordinate first
+// min_dist(s, 0, s.size())
+ld min_dist(const vector<V>& s, int l, int r) {
+    if (r - l <= 5) {
+        ld ret = 1e100;
+        for (int i = l; i < r; i++) {
+            for (int j = i + 1; j < r; j++) {
+                ret = min(ret, dist(s[i], s[j]));
+            }
+        }
+        return ret;
+    }
+    int m = (l + r) >> 1;
+    ld ret = min(min_dist(s, l, m), min_dist(s, m, r));
+    vector<V> q;
+    for (int i = l; i < r; i++) {
+        if (abs(s[i].x - s[m].x) <= ret) q.push_back(s[i]);
+    }
+    sort(q.begin(), q.end(), [](const V& a, const V& b) { return a.y < b.y; });
+    for (int i = 1; i < q.size(); i++) {
+        for (int j = i - 1; j >= 0 && q[j].y >= q[i].y - ret; j--) {
+            ret = min(ret, dist(q[i], q[j]));
+        }
+    }
+    return ret;
+}
+```
+
+### circle
+
+```cpp
+struct C {
+    V o;
+    ld r;
+    C(const V& o, ld r) : o(o), r(r) {}
+};
+
+// find the tangent line to a circle and return the tangent point
+vector<V> tangent_point(const C& c, const V& p) {
+    ld k = c.r / dist(c.o, p);
+    if (gt(k, 1)) return vector<V>();
+    if (eq(k, 1)) return {p};
+    V a = V(c.o, p) * k;
+    return {c.o + rot(a, acos(k)), c.o + rot(a, -acos(k))};
+}
+
+// minimum covering circle
+C min_circle_cover(vector<V> a) {
+    shuffle(a.begin(), a.end(), rng);
+    V o = a[0];
+    ld r = 0;
+    int n = a.size();
+    for (int i = 1; i < n; i++) if (gt(dist(a[i], o), r)) {
+        o = a[i]; r = 0;
+        for (int j = 0; j < i; j++) if (gt(dist(a[j], o), r)) {
+            o = (a[i] + a[j]) / 2;
+            r = dist(a[j], o);
+            for (int k = 0; k < j; k++) if (gt(dist(a[k], o), r)) {
+                o = circumcenter(a[i], a[j], a[k]);
+                r = dist(a[k], o);
+            }
+        }
+    }
+    return C(o, r);
+}
+```
+
+### 3D geometry
+
+```cpp
+struct V {
+    ld x, y, z;
+    constexpr V(ld x = 0, ld y = 0, ld z = 0) : x(x), y(y), z(z) {}
+    constexpr V(const V& a, const V& b) : x(b.x - a.x), y(b.y - a.y), z(b.z - a.z) {}
+    V operator+(const V& b) const { return V(x + b.x, y + b.y, z + b.z); }
+    V operator-(const V& b) const { return V(x - b.x, y - b.y, z - b.z); }
+    V operator*(ld k) const { return V(x * k, y * k, z * k); }
+    V operator/(ld k) const { return V(x / k, y / k, z / k); }
+    ld len() const { return sqrt(len2()); }
+    ld len2() const { return x * x + y * y + z * z; }
+};
+
+ostream& operator<<(ostream& os, const V& p) { return os << "(" << p.x << "," << p.y << "," << p.z << ")"; }
+istream& operator>>(istream& is, V& p) { return is >> p.x >> p.y >> p.z; }
+
+ld dist(const V& a, const V& b) { return (b - a).len(); }
+ld dot(const V& a, const V& b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
+V det(const V& a, const V& b) { return V(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); }
+V cross(const V& s, const V& t, const V& o) { return det(V(o, s), V(o, t)); }
+ld mix(const V& a, const V& b, const V& c) { return dot(a, det(b, c)); }
+```
diff --git a/6-Other.md b/6-Other.md
new file mode 100644
index 0000000..7aaae22
--- /dev/null
+++ b/6-Other.md
@@ -0,0 +1,1182 @@
+## Miscellaneous
+
+### binary search
+
+```cpp
+// 二分闭区间[l, r]
+template <class T, class F>
+T min_left(T l, T r, F f) {
+    while (l < r) {
+        T p = l + (r - l) / 2;
+        f(p) ? r = p : l = p + 1;
+    }
+    return l;
+}
+
+template <class T, class F>
+T max_right(T l, T r, F f) {
+    while (l < r) {
+        T p = l + (r - l + 1) / 2;
+        f(p) ? l = p : r = p - 1;
+    }
+    return l;
+}
+```
+
+### ternary search
+
+```cpp
+// 实数范围
+double l, r, mid1, mid2;
+for (int i = 0; i < 75; i++) {
+    mid1 = (l * 5 + r * 4) / 9;
+    mid2 = (l * 4 + r * 5) / 9;
+    if (f(mid1) > f(mid2)) r = mid2; // 单峰函数取'>'号,单谷函数取'<'号
+    else l = mid1;
+}
+
+// 整数范围
+int l, r, mid1, mid2;
+while (l < r - 2) {
+    mid1 = (l + r) / 2;
+    mid2 = mid1 + 1;
+    if (f(mid1) > f(mid2)) r = mid2; // 单峰函数取'>'号,单谷函数取'<'号
+    else l = mid1;
+}
+int maxval = f(l), ans = l;
+for (int i = l + 1; i <= r; i++) {
+    if (umax(maxval, f(i))) ans = i;
+}
+```
+
+### date
+
+```cpp
+// 0 ~ 6 对应 周一 ~ 周日
+int zeller(int y, int m, int d) {
+    if (m <= 2) m += 12, y--;
+    return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
+}
+
+// date_to_int(1, 1, 1) = 1721426
+// date_to_int(2019, 10, 27) = 2458784
+int date_to_int(int y, int m, int d) {
+    return
+    1461 * (y + 4800 + (m - 14) / 12) / 4 +
+    367 * (m - 2 - (m - 14) / 12 * 12) / 12 -
+    3 * ((y + 4900 + (m - 14) / 12) / 100) / 4 +
+    d - 32075;
+}
+
+void int_to_date(int jd, int &y, int &m, int &d) {
+    int x, n, i, j;
+
+    x = jd + 68569;
+    n = 4 * x / 146097;
+    x -= (146097 * n + 3) / 4;
+    i = (4000 * (x + 1)) / 1461001;
+    x -= 1461 * i / 4 - 31;
+    j = 80 * x / 2447;
+    d = x - 2447 * j / 80;
+    x = j / 11;
+    m = j + 2 - 12 * x;
+    y = 100 * (n - 49) + i + x;
+}
+```
+
+### subset enumeration
+
+```cpp
+// all proper subset
+for (int t = (x - 1) & x; t; t = (t - 1) & x)
+
+// subset of length k
+// Note: k cannot be 0
+void subset(int k, int n) {
+    int t = (1 << k) - 1;
+    while (t < (1 << n)) {
+        // do something
+        int x = t & -t, y = t + x;
+        t = ((t & ~y) / x >> 1) | y;
+    }
+}
+```
+
+### longest non-decreasing subsequence
+
+```cpp
+template <class T>
+int lis(const vector<T>& a) {
+    vector<T> dp(a.size() + 1, numeric_limits<T>::max());
+    T mx = dp[0];
+    for (auto& x : a) *upper_bound(dp.begin(), dp.end(), x) = x;  // use lower_bound for increasing
+    int ans = 0;
+    while (dp[ans] != mx) ++ans;
+    return ans;
+}
+```
+
+### Gray code
+
+```cpp
+int g(int n) { return n ^ (n >> 1); }
+
+int rev_g(int g) {
+    int n = 0;
+    for (; g; g >>= 1) n ^= g;
+    return n;
+}
+```
+
+### digit DP
+
+```cpp
+// Kick Start 2022 数位和整除数位积的数的个数
+const int N = 110;
+ll dp[15][N][N], a[15];
+int mod;
+
+ll dfs(int pos, int sum, int tot, bool limit) {
+    if (sum > mod) return 0;
+    if (pos == -1) return (sum == mod) && (tot == 0);
+    if (!limit && dp[pos][sum][tot] != -1) return dp[pos][sum][tot];
+    ll ret = 0;
+    int ed = limit ? a[pos] : 9;
+    for (int i = 0; i <= ed; i++) {
+        ret += dfs(pos - 1, sum + i, (sum == 0 && i == 0) ? 1 : (tot * i) % mod, limit && i == a[pos]);
+    }
+    if (!limit) dp[pos][sum][tot] = ret;
+    return ret;
+}
+
+ll cal(ll x) {
+    ll sz = 0;
+    while (x) {
+        a[sz++] = x % 10;
+        x /= 10;
+    }
+    ll ans = 0;
+    for (mod = 1; mod < N; mod++) {
+        memset(dp, -1, sizeof(dp));
+        ans += dfs(sz - 1, 0, 1, true);
+    }
+    return ans;
+}
+
+// 小于等于 x 的 base 进制下回文数个数
+ll dp[20][20][20][2], tmp[20], a[20];
+
+ll dfs(ll base, ll pos, ll len, ll s, bool limit) {
+    if (pos == -1) return s;
+    if (!limit && dp[base][pos][len][s] != -1) return dp[base][pos][len][s];
+    ll ret = 0;
+    ll ed = limit ? a[pos] : base - 1;
+    for (int i = 0; i <= ed; i++) {
+        tmp[pos] = i;
+        if (len == pos)
+            ret += dfs(base, pos - 1, len - (i == 0), s, limit && i == a[pos]);
+        else if (s && pos < (len + 1) / 2)
+            ret += dfs(base, pos - 1, len, tmp[len - pos] == i, limit && i == a[pos]);
+        else
+            ret += dfs(base, pos - 1, len, s, limit && i == a[pos]);
+    }
+    if (!limit) dp[base][pos][len][s] = ret;
+    return ret;
+}
+
+ll solve(ll x, ll base) {
+    memset(dp, -1, sizeof(dp));
+    ll sz = 0;
+    while (x) {
+        a[sz++] = x % base;
+        x /= base;
+    }
+    return dfs(base, sz - 1, sz - 1, 1, true);
+}
+```
+
+### random set
+
+```cpp
+vector<int> randset(int l, int r, int k) {
+    // assert(l <= r && k <= r - l + 1);
+    unordered_map<int, int> p;
+    for (int i = l; i < l + k; i++) p[i] = i;
+    for (int i = l; i < l + k; i++) {
+        int j = randint(i, r);
+        if (!p.count(j)) p[j] = j;
+        swap(p[i], p[j]);
+    }
+    vector<int> a(k);
+    for (int i = 0; i < k; i++) a[i] = p[i + l];
+    return a;
+}
+```
+
+### expression evaluation
+
+```py
+print(input()) # Python2
+print(eval(input())) # Python3
+```
+
+### stress test
+
++ *unix
+
+```bash
+#!/bin/bash
+cd "$(dirname "${BASH_SOURCE[0]}")"
+
+g++ gen.cpp -o gen -O2 -std=c++11
+g++ my.cpp -o my -O2 -std=c++11
+g++ std.cpp -o std -O2 -std=c++11
+
+while true
+do
+    ./gen > in.txt
+    ./std < in.txt > stdout.txt
+    ./my < in.txt > myout.txt
+
+    if test $? -ne 0
+    then
+        printf "RE\n"
+        exit 0
+    fi
+
+    if diff stdout.txt myout.txt
+    then
+        printf "AC\n"
+    else
+        printf "WA\n"
+        exit 0
+    fi
+done
+```
+
++ Windows
+
+```
+@echo off
+
+g++ gen.cpp -o gen.exe -O2 -std=c++11
+g++ my.cpp -o my.exe -O2 -std=c++11
+g++ std.cpp -o std.exe -O2 -std=c++11
+
+:loop
+    gen.exe > in.txt
+    std.exe < in.txt > stdout.txt
+    my.exe < in.txt > myout.txt
+    if errorlevel 1 (
+        echo RE
+        pause
+        exit
+    )
+    fc stdout.txt myout.txt
+    if errorlevel 1 (
+        echo WA
+        pause
+        exit
+    )
+goto loop
+```
+
+### pb_ds
+
+```cpp
+// BST
+#include <ext/pb_ds/assoc_container.hpp>
+using namespace __gnu_pbds;
+template<class T>
+using rank_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
+template<class Key, class T>
+using rank_map = tree<Key, T, less<Key>, rb_tree_tag, tree_order_statistics_node_update>;
+
+// priority queue
+#include <ext/pb_ds/priority_queue.hpp>
+using namespace __gnu_pbds;
+template<class T, class Cmp = less<T> >
+using pair_heap = __gnu_pbds::priority_queue<T, Cmp>;
+```
+
+### safe vector
+
+```cpp
+namespace std {
+template<class T>
+class vector_s : public vector<T> {
+public:
+    vector_s(size_t n = 0, const T& x = T()) : vector<T>(n, x) {}
+    T& operator [] (size_t n) { return this->at(n); }
+    const T& operator [] (size_t n) const { return this->at(n); }
+};
+}
+
+#define vector vector_s
+```
+
+### hash
+
+```cpp
+template<class T1, class T2>
+struct pair_hash {
+    size_t operator () (const pair<T1, T2>& p) const {
+        return hash<T1>()(p.first) * 19260817 + hash<T2>()(p.second);
+    }
+};
+
+unordered_set<pair<int, int>, pair_hash<int, int> > st;
+unordered_map<pair<int, int>, int, pair_hash<int, int> > mp;
+
+struct custom_hash {
+    static uint64_t splitmix64(uint64_t x) {
+        // http://xorshift.di.unimi.it/splitmix64.c
+        x += 0x9e3779b97f4a7c15;
+        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
+        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
+        return x ^ (x >> 31);
+    }
+
+    size_t operator()(uint64_t x) const {
+        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
+        return splitmix64(x + FIXED_RANDOM);
+    }
+};
+
+unordered_map<ll, int, custom_hash> safe_map;
+```
+
+### updmax/min
+
+```cpp
+template <class T, class U> bool umax(T& a, U b) { return a < b ? a = b, 1 : 0; }
+template <class T, class U> bool umin(T& a, U b) { return a > b ? a = b, 1 : 0; }
+```
+
+### split/join
+
+```cpp
+vector<string> split(const string& s, string sep) {
+    size_t b = 0, e;
+    vector<string> res;
+    while ((e = s.find(sep, b)) != string::npos) {
+        res.push_back(s.substr(b, e - b));
+        b = e + sep.size();
+    }
+    res.push_back(s.substr(b));
+    return res;
+}
+
+template <class T>
+string join(const vector<T>& v, string sep) {
+    stringstream ss;
+    bool f = 0;
+    for (const T& x : v) (f ? ss << sep : ss) << x, f = 1;
+    return ss.str();
+}
+```
+
+### discretization
+
+```cpp
+// repeating elements with different id
+template<class T>
+vector<int> dc(const vector<T>& a, int start_id) {
+    int n = a.size();
+    vector<pair<T, int> > t(n);
+    for (int i = 0; i < n; i++) {
+        t[i] = make_pair(a[i], i);
+    }
+    sort(t.begin(), t.end());
+    vector<int> id(n);
+    for (int i = 0; i < n; i++) {
+        id[t[i].second] = start_id + i;
+    }
+    return id;
+}
+
+// repeating elements with same id
+template<class T>
+vector<int> unique_dc(const vector<T>& a, int start_id) {
+    int n = a.size();
+    vector<T> t(a);
+    sort(t.begin(), t.end());
+    t.resize(unique(t.begin(), t.end()) - t.begin());
+    vector<int> id(n);
+    for (int i = 0; i < n; i++) {
+        id[i] = start_id + lower_bound(t.begin(), t.end(), a[i]) - t.begin();
+    }
+    return id;
+}
+```
+
+### merge same items
+
+```cpp
+template <class T>
+vector<pair<T, int> > norm(vector<T>& v) {
+    // sort(v.begin(), v.end());
+    vector<pair<T, int> > p;
+    for (int i = 0; i < (int)v.size(); i++) {
+        if (i == 0 || v[i] != v[i - 1])
+            p.emplace_back(v[i], 1);
+        else
+            p.back().second++;
+    }
+    return p;
+}
+```
+
+### enhanced priority queue
+
+```cpp
+struct heap {
+    priority_queue<int> q1, q2;
+    void push(int x) { q1.push(x); }
+    void erase(int x) { q2.push(x); }
+    int top() {
+        while (q2.size() && q1.top() == q2.top()) q1.pop(), q2.pop();
+        return q1.top();
+    }
+    void pop() {
+        while (q2.size() && q1.top() == q2.top()) q1.pop(), q2.pop();
+        q1.pop();
+    }
+    int size() { return q1.size() - q2.size(); }
+};
+```
+
+### fraction
+
+```cpp
+struct Frac {
+    ll x, y;
+
+    Frac(ll p = 0, ll q = 1) {
+        ll d = __gcd(p, q);
+        x = p / d, y = q / d;
+        if (y < 0) x = -x, y = -y;
+    }
+
+    Frac operator + (const Frac& b) { return Frac(x * b.y + y * b.x, y * b.y); }
+    Frac operator - (const Frac& b) { return Frac(x * b.y - y * b.x, y * b.y); }
+    Frac operator * (const Frac& b) { return Frac(x * b.x, y * b.y); }
+    Frac operator / (const Frac& b) { return Frac(x * b.y, y * b.x); }
+};
+
+ostream& operator << (ostream& os, const Frac& f) {
+    if (f.y == 1) return os << f.x;
+    else return os << f.x << '/' << f.y;
+}
+```
+
+### ModInt
+
++ industrial ModInt
+
+```cpp
+// tourist
+template <typename T>
+T inverse(T a, T m) {
+  T u = 0, v = 1;
+  while (a != 0) {
+    T t = m / a;
+    m -= t * a; swap(a, m);
+    u -= t * v; swap(u, v);
+  }
+  assert(m == 1);
+  return u;
+}
+
+template <typename T>
+class Modular {
+ public:
+  using Type = typename decay<decltype(T::value)>::type;
+
+  constexpr Modular() : value() {}
+  template <typename U>
+  Modular(const U& x) {
+    value = normalize(x);
+  }
+
+  template <typename U>
+  static Type normalize(const U& x) {
+    Type v;
+    if (-mod() <= x && x < mod()) v = static_cast<Type>(x);
+    else v = static_cast<Type>(x % mod());
+    if (v < 0) v += mod();
+    return v;
+  }
+
+  const Type& operator()() const { return value; }
+  template <typename U>
+  explicit operator U() const { return static_cast<U>(value); }
+  constexpr static Type mod() { return T::value; }
+
+  Modular& operator+=(const Modular& other) { if ((value += other.value) >= mod()) value -= mod(); return *this; }
+  Modular& operator-=(const Modular& other) { if ((value -= other.value) < 0) value += mod(); return *this; }
+  template <typename U> Modular& operator+=(const U& other) { return *this += Modular(other); }
+  template <typename U> Modular& operator-=(const U& other) { return *this -= Modular(other); }
+  Modular& operator++() { return *this += 1; }
+  Modular& operator--() { return *this -= 1; }
+  Modular operator++(int) { Modular result(*this); *this += 1; return result; }
+  Modular operator--(int) { Modular result(*this); *this -= 1; return result; }
+  Modular operator-() const { return Modular(-value); }
+
+  template <typename U = T>
+  typename enable_if<is_same<typename Modular<U>::Type, int>::value, Modular>::type& operator*=(const Modular& rhs) {
+#ifdef _WIN32
+    uint64_t x = static_cast<int64_t>(value) * static_cast<int64_t>(rhs.value);
+    uint32_t xh = static_cast<uint32_t>(x >> 32), xl = static_cast<uint32_t>(x), d, m;
+    asm(
+      "divl %4; \n\t"
+      : "=a" (d), "=d" (m)
+      : "d" (xh), "a" (xl), "r" (mod())
+    );
+    value = m;
+#else
+    value = normalize(static_cast<int64_t>(value) * static_cast<int64_t>(rhs.value));
+#endif
+    return *this;
+  }
+  template <typename U = T>
+  typename enable_if<is_same<typename Modular<U>::Type, long long>::value, Modular>::type& operator*=(const Modular& rhs) {
+    long long q = static_cast<long long>(static_cast<long double>(value) * rhs.value / mod());
+    value = normalize(value * rhs.value - q * mod());
+    return *this;
+  }
+  template <typename U = T>
+  typename enable_if<!is_integral<typename Modular<U>::Type>::value, Modular>::type& operator*=(const Modular& rhs) {
+    value = normalize(value * rhs.value);
+    return *this;
+  }
+
+  Modular& operator/=(const Modular& other) { return *this *= Modular(inverse(other.value, mod())); }
+
+  friend const Type& abs(const Modular& x) { return x.value; }
+
+  template <typename U>
+  friend bool operator==(const Modular<U>& lhs, const Modular<U>& rhs);
+
+  template <typename U>
+  friend bool operator<(const Modular<U>& lhs, const Modular<U>& rhs);
+
+  template <typename V, typename U>
+  friend V& operator>>(V& stream, Modular<U>& number);
+
+ private:
+  Type value;
+};
+
+template <typename T> bool operator==(const Modular<T>& lhs, const Modular<T>& rhs) { return lhs.value == rhs.value; }
+template <typename T, typename U> bool operator==(const Modular<T>& lhs, U rhs) { return lhs == Modular<T>(rhs); }
+template <typename T, typename U> bool operator==(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) == rhs; }
+
+template <typename T> bool operator!=(const Modular<T>& lhs, const Modular<T>& rhs) { return !(lhs == rhs); }
+template <typename T, typename U> bool operator!=(const Modular<T>& lhs, U rhs) { return !(lhs == rhs); }
+template <typename T, typename U> bool operator!=(U lhs, const Modular<T>& rhs) { return !(lhs == rhs); }
+
+template <typename T> bool operator<(const Modular<T>& lhs, const Modular<T>& rhs) { return lhs.value < rhs.value; }
+
+template <typename T> Modular<T> operator+(const Modular<T>& lhs, const Modular<T>& rhs) { return Modular<T>(lhs) += rhs; }
+template <typename T, typename U> Modular<T> operator+(const Modular<T>& lhs, U rhs) { return Modular<T>(lhs) += rhs; }
+template <typename T, typename U> Modular<T> operator+(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) += rhs; }
+
+template <typename T> Modular<T> operator-(const Modular<T>& lhs, const Modular<T>& rhs) { return Modular<T>(lhs) -= rhs; }
+template <typename T, typename U> Modular<T> operator-(const Modular<T>& lhs, U rhs) { return Modular<T>(lhs) -= rhs; }
+template <typename T, typename U> Modular<T> operator-(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) -= rhs; }
+
+template <typename T> Modular<T> operator*(const Modular<T>& lhs, const Modular<T>& rhs) { return Modular<T>(lhs) *= rhs; }
+template <typename T, typename U> Modular<T> operator*(const Modular<T>& lhs, U rhs) { return Modular<T>(lhs) *= rhs; }
+template <typename T, typename U> Modular<T> operator*(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) *= rhs; }
+
+template <typename T> Modular<T> operator/(const Modular<T>& lhs, const Modular<T>& rhs) { return Modular<T>(lhs) /= rhs; }
+template <typename T, typename U> Modular<T> operator/(const Modular<T>& lhs, U rhs) { return Modular<T>(lhs) /= rhs; }
+template <typename T, typename U> Modular<T> operator/(U lhs, const Modular<T>& rhs) { return Modular<T>(lhs) /= rhs; }
+
+template<typename T, typename U>
+Modular<T> power(const Modular<T>& a, const U& b) {
+  assert(b >= 0);
+  Modular<T> x = a, res = 1;
+  U p = b;
+  while (p > 0) {
+    if (p & 1) res *= x;
+    x *= x;
+    p >>= 1;
+  }
+  return res;
+}
+
+template <typename T>
+bool IsZero(const Modular<T>& number) {
+  return number() == 0;
+}
+
+template <typename T>
+string to_string(const Modular<T>& number) {
+  return to_string(number());
+}
+
+// U == std::ostream? but done this way because of fastoutput
+template <typename U, typename T>
+U& operator<<(U& stream, const Modular<T>& number) {
+  return stream << number();
+}
+
+// U == std::istream? but done this way because of fastinput
+template <typename U, typename T>
+U& operator>>(U& stream, Modular<T>& number) {
+  typename common_type<typename Modular<T>::Type, long long>::type x;
+  stream >> x;
+  number.value = Modular<T>::normalize(x);
+  return stream;
+}
+
+constexpr int md = (int) 1e9 + 7;
+using Mint = Modular<std::integral_constant<decay<decltype(md)>::type, md>>;
+```
+
+### BigInt
+
+```cpp
+// wxh
+class BigInt {
+#define w size()
+
+    static constexpr int base = 1000000000;
+    static constexpr int base_digits = 9;
+
+    using vi = vector<int>;
+    using vll = vector<ll>;
+
+    vi z;
+    int f;
+
+    void trim() {
+        while (!z.empty() && z.back() == 0) {
+            z.pop_back();
+        }
+        if (z.empty()) {
+            f = 1;
+        }
+    }
+
+    void read(const string& s) {
+        f = 1;
+        z.clear();
+        int pos = 0;
+        while (pos < (int)s.w && (s[pos] == '-' || s[pos] == '+')) {
+            if (s[pos] == '-') {
+                f = -f;
+            }
+            ++pos;
+        }
+        for (int i = s.w - 1; i >= pos; i -= base_digits) {
+            int x = 0;
+            for (int j = max(pos, i - base_digits + 1); j <= i; j++) {
+                x = x * 10 + s[j] - '0';
+            }
+            z.push_back(x);
+        }
+        trim();
+    }
+
+    static vi convert_base(const vi& a, int old_digits, int new_digits) {
+        vll p(max(old_digits, new_digits) + 1);
+        p[0] = 1;
+        for (int i = 1; i < (int)p.w; i++) {
+            p[i] = p[i - 1] * 10;
+        }
+        vi res;
+        ll cur = 0;
+        int cur_digits = 0;
+        for (int i = 0; i < (int)a.w; i++) {
+            cur += a[i] * p[cur_digits];
+            cur_digits += old_digits;
+            while (cur_digits >= new_digits) {
+                res.push_back(cur % p[new_digits]);
+                cur /= p[new_digits];
+                cur_digits -= new_digits;
+            }
+        }
+        res.push_back(cur);
+        while (!res.empty() && res.back() == 0) {
+            res.pop_back();
+        }
+        return res;
+    }
+
+    static vll karatsuba(const vll& a, const vll& b) {
+        int n = a.w;
+        vll res(n + n);
+        if (n <= 32) {
+            for (int i = 0; i < n; i++) {
+                for (int j = 0; j < n; j++) {
+                    res[i + j] += a[i] * b[j];
+                }
+            }
+            return res;
+        }
+        int k = n >> 1;
+        vll a1(a.begin(), a.begin() + k);
+        vll a2(a.begin() + k, a.end());
+        vll b1(b.begin(), b.begin() + k);
+        vll b2(b.begin() + k, b.end());
+        vll a1b1 = karatsuba(a1, b1);
+        vll a2b2 = karatsuba(a2, b2);
+        for (int i = 0; i < k; i++) {
+            a2[i] += a1[i];
+        }
+        for (int i = 0; i < k; i++) {
+            b2[i] += b1[i];
+        }
+        vll r = karatsuba(a2, b2);
+        for (int i = 0; i < (int)a1b1.w; i++) {
+            r[i] -= a1b1[i];
+        }
+        for (int i = 0; i < (int)a2b2.w; i++) {
+            r[i] -= a2b2[i];
+        }
+        for (int i = 0; i < (int)r.w; i++) {
+            res[i + k] += r[i];
+        }
+        for (int i = 0; i < (int)a1b1.w; i++) {
+            res[i] += a1b1[i];
+        }
+        for (int i = 0; i < (int)a2b2.w; i++) {
+            res[i + n] += a2b2[i];
+        }
+        return res;
+    }
+
+public:
+    BigInt() : f(1) {}
+    BigInt(ll v) { *this = v; }
+    BigInt(const string& s) { read(s); }
+
+    void operator=(const BigInt& v) {
+        f = v.f;
+        z = v.z;
+    }
+
+    void operator=(ll v) {
+        f = 1;
+        if (v < 0) {
+            f = -1, v = -v;
+        }
+        z.clear();
+        for (; v > 0; v = v / base) {
+            z.push_back(v % base);
+        }
+    }
+
+    BigInt operator+(const BigInt& v) const {
+        if (f == v.f) {
+            BigInt res = v;
+            for (int i = 0, carry = 0; i < (int)max(z.w, v.z.w) || carry; ++i) {
+                if (i == (int)res.z.w) {
+                    res.z.push_back(0);
+                }
+                res.z[i] += carry + (i < (int)z.w ? z[i] : 0);
+                carry = res.z[i] >= base;
+                if (carry) {
+                    res.z[i] -= base;
+                }
+            }
+            return res;
+        } else {
+            return *this - (-v);
+        }
+    }
+
+    BigInt operator-(const BigInt& v) const {
+        if (f == v.f) {
+            if (abs() >= v.abs()) {
+                BigInt res = *this;
+                for (int i = 0, carry = 0; i < (int)v.z.w || carry; ++i) {
+                    res.z[i] -= carry + (i < (int)v.z.w ? v.z[i] : 0);
+                    carry = res.z[i] < 0;
+                    if (carry) {
+                        res.z[i] += base;
+                    }
+                }
+                res.trim();
+                return res;
+            } else {
+                return -(v - *this);
+            }
+        } else {
+            return *this + (-v);
+        }
+    }
+
+    void operator*=(int v) {
+        if (v < 0) {
+            f = -f, v = -v;
+        }
+        for (int i = 0, carry = 0; i < (int)z.w || carry; ++i) {
+            if (i == (int)z.w) {
+                z.push_back(0);
+            }
+            ll cur = (ll)z[i] * v + carry;
+            carry = cur / base;
+            z[i] = cur % base;
+            // asm("divl %%ecx" : "=a"(carry), "=d"(a[i]) : "A"(cur), "c"(base));
+        }
+        trim();
+    }
+
+    BigInt operator*(int v) const {
+        BigInt res = *this;
+        res *= v;
+        return res;
+    }
+
+    friend pair<BigInt, BigInt> divmod(const BigInt& a1, const BigInt& b1) {
+        int norm = base / (b1.z.back() + 1);
+        BigInt a = a1.abs() * norm;
+        BigInt b = b1.abs() * norm;
+        BigInt q, r;
+        q.z.resize(a.z.w);
+        for (int i = a.z.w - 1; i >= 0; i--) {
+            r *= base;
+            r += a.z[i];
+            int s1 = b.z.w < r.z.w ? r.z[b.z.w] : 0;
+            int s2 = b.z.w - 1 < r.z.w ? r.z[b.z.w - 1] : 0;
+            int d = ((ll)s1 * base + s2) / b.z.back();
+            r -= b * d;
+            while (r < 0) {
+                r += b, --d;
+            }
+            q.z[i] = d;
+        }
+        q.f = a1.f * b1.f;
+        r.f = a1.f;
+        q.trim();
+        r.trim();
+        return make_pair(q, r / norm);
+    }
+
+    friend BigInt sqrt(const BigInt& a1) {
+        BigInt a = a1;
+        while (a.z.empty() || (int)a.z.w % 2 == 1) {
+            a.z.push_back(0);
+        }
+        int n = a.z.w;
+        int firstDigit = sqrt((ll)a.z[n - 1] * base + a.z[n - 2]);
+        int norm = base / (firstDigit + 1);
+        a *= norm;
+        a *= norm;
+        while (a.z.empty() || (int)a.z.w % 2 == 1) {
+            a.z.push_back(0);
+        }
+        BigInt r = (ll)a.z[n - 1] * base + a.z[n - 2];
+        firstDigit = sqrt((ll)a.z[n - 1] * base + a.z[n - 2]);
+        int q = firstDigit;
+        BigInt res;
+        for (int j = n / 2 - 1; j >= 0; j--) {
+            for (;; --q) {
+                BigInt r1 = (r - (res * 2 * base + q) * q) * base * base +
+                            (j > 0 ? (ll)a.z[2 * j - 1] * base + a.z[2 * j - 2] : 0);
+                if (r1 >= 0) {
+                    r = r1;
+                    break;
+                }
+            }
+            res *= base;
+            res += q;
+            if (j > 0) {
+                int d1 = res.z.w + 2 < r.z.w ? r.z[res.z.w + 2] : 0;
+                int d2 = res.z.w + 1 < r.z.w ? r.z[res.z.w + 1] : 0;
+                int d3 = res.z.w < r.z.w ? r.z[res.z.w] : 0;
+                q = ((ll)d1 * base * base + (ll)d2 * base + d3) / (firstDigit * 2);
+            }
+        }
+        res.trim();
+        return res / norm;
+    }
+
+    BigInt operator/(const BigInt& v) const { return divmod(*this, v).first; }
+    BigInt operator%(const BigInt& v) const { return divmod(*this, v).second; }
+
+    void operator/=(int v) {
+        if (v < 0) {
+            f = -f, v = -v;
+        }
+        for (int i = z.w - 1, rem = 0; i >= 0; --i) {
+            ll cur = z[i] + (ll)rem * base;
+            z[i] = cur / v;
+            rem = cur % v;
+        }
+        trim();
+    }
+
+    BigInt operator/(int v) const {
+        BigInt res = *this;
+        res /= v;
+        return res;
+    }
+
+    int operator%(int v) const {
+        if (v < 0) {
+            v = -v;
+        }
+        int m = 0;
+        for (int i = z.w - 1; i >= 0; --i) {
+            m = ((ll)m * base + z[i]) % v;
+        }
+        return m * f;
+    }
+
+    void operator+=(const BigInt& v) { *this = *this + v; }
+    void operator-=(const BigInt& v) { *this = *this - v; }
+    void operator*=(const BigInt& v) { *this = *this * v; }
+    void operator/=(const BigInt& v) { *this = *this / v; }
+
+    bool operator<(const BigInt& v) const {
+        if (f != v.f) {
+            return f < v.f;
+        }
+        if (z.w != v.z.w) {
+            return z.w * f < v.z.w * v.f;
+        }
+        for (int i = z.w - 1; i >= 0; i--) {
+            if (z[i] != v.z[i]) {
+                return z[i] * f < v.z[i] * f;
+            }
+        }
+        return false;
+    }
+
+    bool operator>(const BigInt& v) const { return v < *this; }
+    bool operator<=(const BigInt& v) const { return !(v < *this); }
+    bool operator>=(const BigInt& v) const { return !(*this < v); }
+    bool operator==(const BigInt& v) const { return !(*this < v) && !(v < *this); }
+    bool operator!=(const BigInt& v) const { return *this < v || v < *this; }
+
+    bool is_zero() const { return z.empty() || ((int)z.w == 1 && !z[0]); }
+
+    BigInt operator-() const {
+        BigInt res = *this;
+        res.f = -f;
+        return res;
+    }
+
+    BigInt abs() const {
+        BigInt res = *this;
+        res.f *= res.f;
+        return res;
+    }
+
+    ll long_value() const {
+        ll res = 0;
+        for (int i = z.w - 1; i >= 0; i--) {
+            res = res * base + z[i];
+        }
+        return res * f;
+    }
+
+    friend BigInt gcd(const BigInt& a, const BigInt& b) { return b.is_zero() ? a : gcd(b, a % b); }
+    friend BigInt lcm(const BigInt& a, const BigInt& b) { return a / gcd(a, b) * b; }
+
+    friend istream& operator>>(istream& is, BigInt& v) {
+        string s;
+        is >> s;
+        v.read(s);
+        return is;
+    }
+
+    friend ostream& operator<<(ostream& os, const BigInt& v) {
+        if (v.f == -1) {
+            os << '-';
+        }
+        os << (v.z.empty() ? 0 : v.z.back());
+        for (int i = v.z.w - 2; i >= 0; --i) {
+            os << setw(base_digits) << setfill('0') << v.z[i];
+        }
+        return os;
+    }
+
+    BigInt operator*(const BigInt& v) const {
+        vi a6 = convert_base(this->z, base_digits, 6);
+        vi b6 = convert_base(v.z, base_digits, 6);
+        vll a(a6.begin(), a6.end());
+        vll b(b6.begin(), b6.end());
+        while (a.w < b.w) {
+            a.push_back(0);
+        }
+        while (b.w < a.w) {
+            b.push_back(0);
+        }
+        while (a.w & (a.w - 1)) {
+            a.push_back(0);
+            b.push_back(0);
+        }
+        vll c = karatsuba(a, b);
+        BigInt res;
+        res.f = f * v.f;
+        for (int i = 0, carry = 0; i < (int)c.w; i++) {
+            ll cur = c[i] + carry;
+            res.z.push_back(cur % 1000000);
+            carry = cur / 1000000;
+        }
+        res.z = convert_base(res.z, 6, base_digits);
+        res.trim();
+        return res;
+    }
+
+#undef w
+};
+```
+
+### Java
+
++ Main
+
+```java
+import java.io.*;
+import java.util.*;
+
+public class Main {
+    public static void main(String[] args) {
+        Scanner in = new Scanner(System.in);
+        PrintStream out = System.out;
+
+    }
+}
+```
+
++ Petr's ultimate fast input
+
+```java
+public class Main {
+    public static void main(String[] args) {
+        InputStream inputStream = System.in;
+        OutputStream outputStream = System.out;
+        InputReader in = new InputReader(inputStream);
+        PrintWriter out = new PrintWriter(outputStream);
+
+        out.close();
+    }
+
+    static class InputReader {
+        public BufferedReader reader;
+        public StringTokenizer tokenizer;
+
+        public InputReader(InputStream stream) {
+            reader = new BufferedReader(new InputStreamReader(stream), 32768);
+            tokenizer = null;
+        }
+
+        public String next() {
+            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
+                try {
+                    tokenizer = new StringTokenizer(reader.readLine());
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            return tokenizer.nextToken();
+        }
+
+        public int nextInt() {
+            return Integer.parseInt(next());
+        }
+    }
+}
+```
+
++ BigInteger
+
+```java
+import java.math.BigInteger;
+
+BigInteger.ZERO
+BigInteger.ONE
+BigInteger.TWO // since Java 9
+BigInteger.TEN
+BigInteger.valueOf(2)
+
+BigInteger abs()
+BigInteger negate() // -this
+
+BigInteger add​(BigInteger x)
+BigInteger subtract​(BigInteger x)
+BigInteger multiply​(BigInteger x)
+BigInteger divide​(BigInteger x)
+
+BigInteger pow​(int exp)
+BigInteger sqrt() // since Java 9
+
+BigInteger mod​(BigInteger m)
+BigInteger modPow​(BigInteger exp, BigInteger m)
+BigInteger modInverse​(BigInteger m)
+
+boolean isProbablePrime​(int certainty) // probability: 1 - (1/2) ^ (certainty)
+
+BigInteger gcd​(BigInteger x)
+
+BigInteger not() // ~this
+BigInteger and​(BigInteger x)
+BigInteger or​(BigInteger x)
+BigInteger xor​(BigInteger x)
+BigInteger shiftLeft​(int n)
+BigInteger shiftRight​(int n)
+
+int compareTo​(BigInteger x) // -1, 0, 1
+BigInteger max​(BigInteger x)
+BigInteger min​(BigInteger x)
+
+int intValue()
+long longValue()
+String toString()
+
+public static BigInteger getsqrt(BigInteger n) {
+    if (n.compareTo(BigInteger.ZERO) <= 0) return n;
+    BigInteger x, xx, txx;
+    xx = x = BigInteger.ZERO;
+    for (int t = n.bitLength() / 2; t >= 0; t--) {
+        txx = xx.add(x.shiftLeft(t + 1)).add(BigInteger.ONE.shiftLeft(t + t));
+        if (txx.compareTo(n) <= 0) {
+            x = x.add(BigInteger.ONE.shiftLeft(t));
+            xx = txx;
+        }
+    }
+    return x;
+}
+```
+
++ DecimalFormat
+
+```java
+import java.text.DecimalFormat;
+
+DecimalFormat fmt;
+
+// String s = fmt.format(...)
+
+// round to at most 2 digits, leave of digits if not needed
+fmt = new DecimalFormat("#.##");
+// 12345.6789 -> "12345.68"
+// 12345.0 -> "12345"
+// 0.0 -> "0"
+// 0.01 -> ".1"
+
+// round to precisely 2 digits
+fmt = new DecimalFormat("#.00");
+// 12345.6789 -> "12345.68"
+// 12345.0 -> "12345.00"
+// 0.0 -> ".00"
+
+// round to precisely 2 digits, force leading zero
+fmt = new DecimalFormat("0.00");
+// 12345.6789 -> "12345.68"
+// 12345.0 -> "12345.00"
+// 0.0 -> "0.00"
+
+// round to precisely 2 digits, force leading zeros
+fmt = new DecimalFormat("000000000.00");
+// 12345.6789 -> "000012345.68"
+// 12345.0 -> "000012345.00"
+// 0.0 -> "000000000.00"
+```
diff --git a/9-Unverified.md b/9-Unverified.md
new file mode 100644
index 0000000..63d8332
--- /dev/null
+++ b/9-Unverified.md
@@ -0,0 +1,766 @@
+## 待验证
+
+**版权归原作者所有 部分代码有风格调整 不保证内容的正确性**
+
+### 约瑟夫问题
+
+```cpp
+// n个人,1至m报数,问最后留下来的人的编号
+// 公式:f(n,m)=(f(n−1,m)+m)%n,f(0,m)=0;
+// O(n)
+ll calc(int n, ll m) {
+    ll p = 0;
+    for (int i = 2; i <= n; i++) {
+        p = (p + m) % i;
+    }
+    return p + 1;
+}
+
+// n个人,1至m报数,问第k个出局的人的编号
+// 公式:f(n,k)=(f(n−1,k−1)+m−1)%n+1
+// f(n−k+1,1)=m%(n−k+1)
+// if (f==0) f=n−k+1
+// O(k)
+ll cal1(ll n, ll m, ll k) {  // (k == n) equal(calc)
+    ll p = m % (n - k + 1);
+    if (p == 0) p = n - k + 1;
+    for (ll i = 2; i <= k; i++) {
+        p = (p + m - 1) % (n - k + i) + 1;
+    }
+    return p;
+}
+
+// n个人,1至m报数,问第k个出局的人的编号
+// O(m*log(m))
+ll cal2(ll n, ll m, ll k) {
+    if (m == 1)
+        return k;
+    else {
+        ll a = n - k + 1, b = 1;
+        ll c = m % a, x = 0;
+        if (c == 0) c = a;
+        while (b + x <= k) {
+            a += x, b += x, c += m * x;
+            c %= a;
+            if (c == 0) c = a;
+            x = (a - c) / (m - 1) + 1;
+        }
+        c += (k - b) * m;
+        c %= n;
+        if (c == 0) c = n;
+        return c;
+    }
+}
+
+// n个人,1至m报数,问编号为k的人是第几个出局的
+// O(n)
+ll n, k;  //可做n<=4e7,询问个数<=100,下标范围[0,n-1]
+ll dieInXturn(int n, int k, int x) {  // n个人,报数k,下标为X的人第几个死亡
+    ll tmp = 0;
+    while (n) {
+        x = (x + n) % n;
+        if (k > n) x += (k - x - 1 + n - 1) / n * n;
+        if ((x + 1) % k == 0) {
+            tmp += (x + 1) / k;
+            break;
+        } else {
+            if (k > n) {
+                tmp += x / k;
+                ll ttmp = x;
+                x = x - (x / n + 1) * (x / k) + (x + n) / n * n - k;
+                n -= ttmp / k;
+            } else {
+                tmp += n / k;
+                x = x - x / k;
+                x += n - n / k * k;
+                n -= n / k;
+            }
+        }
+    }
+    return tmp;
+}
+```
+
+### 二分图最大权匹配KM
+
+```cpp
+// ECNU
+namespace R {
+    int n;
+    int w[N][N], kx[N], ky[N], py[N], vy[N], slk[N], pre[N];
+
+    ll go() {
+        for (int i = 1; i <= n; i++)
+            for (int j = 1; j <= n; j++)
+                kx[i] = max(kx[i], w[i][j]);
+        for (int i = 1; i <= n; i++) {
+            fill(vy, vy + n + 1, 0);
+            fill(slk, slk + n + 1, INF);
+            fill(pre, pre + n + 1, 0);
+            int k = 0, p = -1;
+            for (py[k = 0] = i; py[k]; k = p) {
+                int d = INF;
+                vy[k] = 1;
+                int x = py[k];
+                for (int j = 1; j <= n; j++) {
+                    if (!vy[j]) {
+                        int t = kx[x] + ky[j] - w[x][j];
+                        if (t < slk[j]) { slk[j] = t; pre[j] = k; }
+                        if (slk[j] < d) { d = slk[j]; p = j; }
+                    }
+                }
+                for (int j = 0; j <= n; j++) {
+                    if (vy[j]) { kx[py[j]] -= d; ky[j] += d; }
+                    else slk[j] -= d;
+                }
+            }
+            for (; k; k = pre[k]) py[k] = py[pre[k]];
+        }
+        ll ans = 0;
+        for (int i = 1; i <= n; i++) ans += kx[i] + ky[i];
+        return ans;
+    }
+}
+```
+
+### HLPP
+
+```cpp
+struct HLPP {
+    struct Edge {
+        int v, rev;
+        ll cap;
+    };
+    int n, sp, tp, lim, ht, lcnt;
+    ll exf[N];
+    vector<Edge> G[N];
+    vector<int> hq[N], gap[N], h, sum;
+    void init(int nn, int s, int t) {
+        sp = s, tp = t, n = nn, lim = n + 1, ht = lcnt = 0;
+        for (int i = 1; i <= n; ++i) G[i].clear(), exf[i] = 0;
+    }
+    void add_edge(int u, int v, ll cap) {
+        G[u].push_back({v, int(G[v].size()), cap});
+        G[v].push_back({u, int(G[u].size()) - 1, 0});
+    }
+    void update(int u, int nh) {
+        ++lcnt;
+        if (h[u] != lim) --sum[h[u]];
+        h[u] = nh;
+        if (nh == lim) return;
+        ++sum[ht = nh];
+        gap[nh].push_back(u);
+        if (exf[u] > 0) hq[nh].push_back(u);
+    }
+    void relabel() {
+        queue<int> q;
+        for (int i = 0; i <= lim; ++i) hq[i].clear(), gap[i].clear();
+        h.assign(lim, lim), sum.assign(lim, 0), q.push(tp);
+        lcnt = ht = h[tp] = 0;
+        while (!q.empty()) {
+            int u = q.front();
+            q.pop();
+            for (Edge& e : G[u])
+                if (h[e.v] == lim && G[e.v][e.rev].cap) update(e.v, h[u] + 1), q.push(e.v);
+            ht = h[u];
+        }
+    }
+    void push(int u, Edge& e) {
+        if (!exf[e.v]) hq[h[e.v]].push_back(e.v);
+        ll df = min(exf[u], e.cap);
+        e.cap -= df, G[e.v][e.rev].cap += df;
+        exf[u] -= df, exf[e.v] += df;
+    }
+    void discharge(int u) {
+        int nh = lim;
+        if (h[u] == lim) return;
+        for (Edge& e : G[u]) {
+            if (!e.cap) continue;
+            if (h[u] == h[e.v] + 1) {
+                push(u, e);
+                if (exf[u] <= 0) return;
+            } else if (nh > h[e.v] + 1)
+                nh = h[e.v] + 1;
+        }
+        if (sum[h[u]] > 1)
+            update(u, nh);
+        else {
+            for (; ht >= h[u]; gap[ht--].clear())
+                for (int& i : gap[ht]) update(i, lim);
+        }
+    }
+    ll hlpp() {
+        exf[sp] = INF, exf[tp] = -INF, relabel();
+        for (Edge& e : G[sp]) push(sp, e);
+        for (; ~ht; --ht) {
+            while (!hq[ht].empty()) {
+                int u = hq[ht].back();
+                hq[ht].pop_back();
+                discharge(u);
+                if (lcnt > (n << 2)) relabel();
+            }
+        }
+        return exf[tp] + INF;
+    }
+};
+```
+
+### 上下界网络流
+
+```cpp
+const int INF = 0x3f3f3f3f;
+
+struct edge {
+    int to, cap, rev;
+};
+
+const int N = 60003;
+const int M = 400003;
+
+struct graph {
+    int n, m;
+    edge w[M];
+    int fr[M];
+    int num[N], cur[N], first[N];
+    edge e[M];
+
+    void init(int n) {
+        this->n = n;
+        m = 0;
+    }
+
+    void add_edge(int from, int to, int cap) {
+        w[++m] = (edge){to, cap};
+        num[from]++, fr[m] = from;
+        w[++m] = (edge){from, 0};
+        num[to]++, fr[m] = to;
+    }
+
+    void prepare() {
+        first[1] = 1;
+        for (int i = 2; i <= n; i++) first[i] = first[i - 1] + num[i - 1];
+        for (int i = 1; i < n; i++) num[i] = first[i + 1] - 1;
+        num[n] = m;
+        for (int i = 1; i <= m; i++) {
+            e[first[fr[i]] + (cur[fr[i]]++)] = w[i];
+
+            if (!(i % 2)) {
+                e[first[fr[i]] + cur[fr[i]] - 1].rev =
+                    first[w[i].to] + cur[w[i].to] - 1;
+                e[first[w[i].to] + cur[w[i].to] - 1].rev =
+                    first[fr[i]] + cur[fr[i]] - 1;
+            }
+        }
+    }
+
+    int q[N];
+    int dist[N];
+    int t;
+
+    bool bfs(int s) {
+        int l = 1, r = 1;
+        q[1] = s;
+        memset(dist, -1, (n + 1) * 4);
+        dist[s] = 0;
+        while (l <= r) {
+            int u = q[l++];
+            for (int i = first[u]; i <= num[u]; i++) {
+                int v = e[i].to;
+                if ((dist[v] != -1) || (!e[i].cap)) continue;
+                dist[v] = dist[u] + 1;
+                if (v == t) return true;
+                q[++r] = v;
+            }
+        }
+        return dist[t] != -1;
+    }
+
+    int dfs(int u, int flow) {
+        if (u == t) return flow;
+        for (int& i = cur[u]; i <= num[u]; i++) {
+            int v = e[i].to;
+            if (!e[i].cap || dist[v] != dist[u] + 1) continue;
+            int t = dfs(v, min(flow, e[i].cap));
+            if (t) {
+                e[i].cap -= t;
+                e[e[i].rev].cap += t;
+                return t;
+            }
+        }
+        return 0;
+    }
+
+    ll dinic(int s, int t) {
+        ll ans = 0;
+        this->t = t;
+        while (bfs(s)) {
+            int flow;
+            for (int i = 1; i <= n; i++) cur[i] = first[i];
+            while (flow = dfs(s, INF)) ans += (ll)flow;
+        }
+        return ans;
+    }
+};
+
+struct graph_bounds {
+    int in[N];
+    int S, T, sum, cur;
+    graph g;
+    int n;
+
+    void init(int n) {
+        this->n = n;
+        S = n + 1;
+        T = n + 2;
+        sum = 0;
+        g.init(n + 2);
+    }
+
+    void add_edge(int from, int to, int low, int up) {
+        g.add_edge(from, to, up - low);
+        in[to] += low;
+        in[from] -= low;
+    }
+
+    void build() {
+        for (int i = 1; i <= n; i++)
+            if (in[i] > 0)
+                g.add_edge(S, i, in[i]), sum += in[i];
+            else if (in[i])
+                g.add_edge(i, T, -in[i]);
+        g.prepare();
+    }
+
+    bool canflow() {
+        build();
+        int flow = g.dinic(S, T);
+        return flow >= sum;
+    }
+
+    bool canflow(int s, int t) {
+        g.add_edge(t, s, INF);
+        build();
+        for (int i = 1; i <= g.m; i++) {
+            edge& e = g.e[i];
+            if (e.to == s && e.cap == INF) {
+                cur = i;
+                break;
+            }
+        }
+        int flow = g.dinic(S, T);
+        return flow >= sum;
+    }
+
+    int maxflow(int s, int t) {
+        if (!canflow(s, t)) return -1;
+        return g.dinic(s, t);
+    }
+
+    int minflow(int s, int t) {
+        if (!canflow(s, t)) return -1;
+        edge& e = g.e[cur];
+        int flow = INF - e.cap;
+        e.cap = g.e[e.rev].cap = 0;
+        return flow - g.dinic(t, s);
+    }
+} g;
+
+void solve() {
+    int n = read(), m = read(), s = read(), t = read();
+    g.init(n);
+    while (m--) {
+        int u = read(), v = read(), low = read(), up = read();
+        g.add_edge(u, v, low, up);
+    }
+}
+```
+
+### Link-Cut Tree
+
+```cpp
+// Chestnut
+const int N = 50005;
+
+#define lc son[x][0]
+#define rc son[x][1]
+
+struct Splay {
+    int fa[N], son[N][2];
+    int st[N];
+    bool rev[N];
+    inline int which(int x) {
+        for (int i = 0; i < 2; i++)
+            if (son[fa[x]][i] == x) return i;
+        return -1;
+    }
+
+    inline void pushdown(int x) {
+        if (rev[x]) {
+            rev[x] ^= 1;
+            rev[lc] ^= 1;
+            rev[rc] ^= 1;
+            swap(lc, rc);
+        }
+    }
+    
+    inline void rotate(int x) {
+        int f = fa[x], w = which(x) ^ 1, c = son[x][w];
+        fa[x] = fa[f];
+        if (which(f) != -1) son[fa[f]][which(f)] = x;
+        fa[c] = f;
+        son[f][w ^ 1] = c;
+        fa[f] = x;
+        son[x][w] = f;
+    }
+
+    inline void splay(int x) {
+        int top = 0;
+        st[++top] = x;
+        for (int i = x; which(i) != -1; i = fa[i]) {
+            st[++top] = fa[i];
+        }
+        for (int i = top; i; i--) pushdown(st[i]);
+        while (which(x) != -1) {
+            int f = fa[x];
+            if (which(f) != -1) {
+                if (which(x) ^ which(f)) rotate(x);
+                else rotate(f);
+            }
+            rotate(x);
+        }
+    }
+
+    void access(int x) {
+        int t = 0;
+        while (x) {
+            splay(x);
+            rc = t;
+            t = x;
+            x = fa[x];
+        }
+    }
+
+    void rever(int x) {
+        access(x);
+        splay(x);
+        rev[x] ^= 1;
+    }
+
+    void link(int x, int y) {
+        rever(x);
+        fa[x] = y;
+        splay(x);
+    }
+
+    void cut(int x, int y) {
+        rever(x);
+        access(y);
+        splay(y);
+        son[y][0] = fa[x] = 0;
+    }
+
+    int find(int x) {
+        access(x);
+        splay(x);
+        int y = x;
+        while (son[y][0]) y = son[y][0];
+        return y;
+    }
+} T;
+
+int n, m;
+
+int main() {
+    char ch[10];
+    int x, y;
+    scanf("%d%d", &n, &m);
+    for (int i = 1; i <= m; i++) {
+        scanf("%s", ch);
+        scanf("%d%d", &x, &y);
+        if (ch[0] == 'C') T.link(x, y);
+        else if (ch[0] == 'D') T.cut(x, y);
+        else {
+            if (T.find(x) == T.find(y)) printf("Yes\n");
+            else printf("No\n");
+        }
+    }
+}
+```
+
+### 回文自动机
+
+```cpp
+// WindJ0Y
+struct Palindromic_Tree {
+    static constexpr int N = 300005;
+
+    int next[N][26]; // next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
+    int fail[N]; // fail指针,失配后跳转到fail指针指向的节点
+    int cnt[N]; // 表示节点i表示的本质不同的串的个数 after count()
+    int num[N]; // 表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。
+    int len[N]; // len[i]表示节点i表示的回文串的长度
+    int lcnt[N];
+    int S[N]; // 存放添加的字符
+    int last; // 指向上一个字符所在的节点,方便下一次add
+    int n; // 字符数组指针
+    int p; // 节点指针
+
+    int newnode(int l, int vc) { // 新建节点
+        for (int i = 0; i < 26; ++i) next[p][i] = 0;
+        cnt[p] = 0;
+        num[p] = 0;
+        len[p] = l;
+        lcnt[p] = vc;
+        return p++;
+    }
+
+    void init() { // 初始化
+        p = 0;
+        newnode(0, 0);
+        newnode(-1, 0);
+        last = 0;
+        n = 0;
+        S[n] = -1; // 开头放一个字符集中没有的字符,减少特判
+        fail[0] = 1;
+    }
+
+    int get_fail(int x) { // 和KMP一样,失配后找一个尽量最长的
+        while (S[n - len[x] - 1] != S[n]) x = fail[x];
+        return x;
+    }
+
+    void add(int c) {
+        S[++n] = c;
+        int cur = get_fail(last); // 通过上一个回文串找这个回文串的匹配位置
+        if (!next[cur][c]) { // 如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
+            int now = newnode(len[cur] + 2, lcnt[cur] | (1 << c)); // 新建节点
+            fail[now] = next[get_fail(fail[cur])][c]; // 和AC自动机一样建立fail指针,以便失配后跳转
+            next[cur][c] = now;
+            num[now] = num[fail[now]] + 1;
+        }
+        last = next[cur][c];
+        cnt[last]++;
+    }
+
+    void count() {
+        for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i];
+        // 父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串
+    }
+} pt;
+```
+
+### 任意模数 NTT
+
+```cpp
+// memset0
+const int N = 4e5 + 10, G = 3, P[3] = {469762049, 998244353, 1004535809};
+int n1, n2, k, n, p, p1, p2, M2;
+int a[N], b[N], f[3][N], g[N], rev[N], ans[N];
+
+void ntt(int *a, int g, int p) {
+    for (int i = 0; i < n; i++) if (i < rev[i]) swap(a[i], a[rev[i]]);
+    for (int len = 1; len < n; len <<= 1) {
+        int wn = qk(g, (p - 1) / (len << 1), p);
+        for (int i = 0; i < n; i += (len << 1)) {
+            int w = 1;
+            for (int j = 0; j < len; j++, w = (ll)w * wn % p) {
+                int x = a[i + j], y = (ll)w * a[i + j + len] % p;
+                a[i + j] = (x + y) % p, a[i + j + len] = (x - y + p) % p;
+            }
+        }
+    }
+}
+
+int merge(int a1, int a2, int A2) {
+    ll M1 = (ll)p1 * p2;
+    ll A1 = ((ll)inv(p2, p1) * a1 % p1 * p2 + (ll)inv(p1, p2) * a2 % p2 * p1) % M1;
+    ll K = ((A2 - A1) % M2 + M2) % M2 * inv(M1 % M2, M2) % M2;
+    int ans = (A1 + M1 % p * K) % p;
+    return ans;
+}
+
+void go() {
+    read(n1), read(n2), read(p);
+    p1 = P[0], p2 = P[1], M2 = P[2];
+    for (int i = 0; i <= n1; i++) read(a[i]);
+    for (int i = 0; i <= n2; i++) read(b[i]);
+    n = 1; while (n <= (n1 + n2)) n <<= 1, ++k;
+    for (int i = 0; i < n; i++) {
+        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
+    }
+    for (int k = 0; k < 3; k++) {
+        for (int i = 0; i < n; i++) f[k][i] = a[i] % P[k];
+        for (int i = 0; i < n; i++) g[i] = b[i] % P[k];
+        ntt(f[k], G, P[k]), ntt(g, G, P[k]);
+        for (int i = 0; i < n; i++) f[k][i] = (ll)f[k][i] * g[i] % P[k];
+        ntt(f[k], inv(G, P[k]), P[k]);
+        for (int i = 0; i < n; i++) f[k][i] = (ll)f[k][i] * inv(n, P[k]) % P[k];
+    }
+    for (int i = 0; i <= n1 + n2; i++) ans[i] = merge(f[0][i], f[1][i], f[2][i]);
+}
+```
+
+### 计算几何
+
+```cpp
+// 经纬度球面最短距离
+// Voleking
+ld Dist(ld la1, ld lo1, ld la2, ld lo2, ld R) {
+    la1 *= PI / 180, lo1 *= PI / 180, la2 *= PI / 180, lo2 *= PI / 180;
+    ld x1 = cos(la1) * sin(lo1), y1 = cos(la1) * cos(lo1), z1 = sin(la1); 
+    ld x2 = cos(la2) * sin(lo2), y2 = cos(la2) * cos(lo2), z1 = sin(la2); 
+    return R * acos(x1 * x2 + y1 * y2 + z1 * z2);
+}
+
+// jiry_2
+int cmp(ld k1, ld k2) {
+    return sgn(k1 - k2);
+}
+V proj(V k1, V k2, V q) { // q 到直线 k1,k2 的投影 
+    V k = k2 - k1;
+    return k1 + k * (dot(q - k1, k) / k.abs2());
+}
+V reflect(V k1, V k2, V q) {
+    return proj(k1, k2, q) * 2 - q;
+}
+int clockwise(V k1, V k2, V k3) { // k1 k2 k3 逆时针 1 顺时针 -1 否则 0  
+    return sgn(det(k2 - k1, k3 - k1));
+}
+int checkLL(V k1, V k2, V k3, V k4) { // 求直线 (L) 线段 (S) k1,k2 和 k3,k4 的交点 
+    return cmp(det(k3 - k1, k4 - k1), det(k3 - k2, k4 - k2)) != 0;
+}
+V getLL(V k1, V k2, V k3, V k4) {
+    ld w1 = det(k1 - k3, k4 - k3), w2 = det(k4 - k3, k2 - k3);
+    return (k1 * w2 + k2 * w1) / (w1 + w2);
+}
+vector<line> getHL(vector<line>& L) { // 求半平面交, 半平面是逆时针方向, 输出按照逆时针
+    sort(L.begin(), L.end());
+    deque<line> q;
+    for (int i = 0; i < (int) L.size(); i++) {
+        if (i && sameDir(L[i], L[i - 1])) continue;
+        while (q.size() > 1 && !checkpos(q[q.size() - 2], q[q.size() - 1], L[i])) q.pop_back();
+        while (q.size() > 1 && !checkpos(q[1], q[0], L[i])) q.pop_front();
+        q.push_back(L[i]);
+    }
+    while (q.size() > 2 && !checkpos(q[q.size() - 2], q[q.size() - 1], q[0])) q.pop_back();
+    while (q.size() > 2 && !checkpos(q[1], q[0], q[q.size() - 1])) q.pop_front();
+    vector<line> ans;
+    for (int i = 0; i < q.size(); i++) ans.push_back(q[i]);
+    return ans;
+}
+int checkposCC(circle k1, circle k2) { // 返回两个圆的公切线数量
+    if (cmp(k1.r, k2.r) == -1) swap(k1, k2);
+    ld dis = k1.o.dis(k2.o);
+    int w1 = cmp(dis, k1.r + k2.r), w2 = cmp(dis, k1.r - k2.r);
+    if (w1 > 0) return 4;
+    else if (w1 == 0) return 3;
+    else if (w2 > 0) return 2;
+    else if (w2 == 0) return 1;
+    else return 0;
+}
+vector<V> getCL(circle k1, V k2, V k3) { // 沿着 k2->k3 方向给出, 相切给出两个 
+    V k = proj(k2, k3, k1.o);
+    ld d = k1.r * k1.r - (k - k1.o).abs2();
+    if (sgn(d) == -1) return {};
+    V del = (k3 - k2).unit() * sqrt(max((ld) 0.0, d));
+    return {k - del, k + del};
+}
+vector<line> TangentoutCC(circle k1, circle k2) {
+    int pd = checkposCC(k1, k2);
+    if (pd == 0) return {};
+    if (pd == 1) {
+        V k = getCC(k1, k2)[0];
+        return { (line){k, k} };
+    }
+    if (cmp(k1.r, k2.r) == 0) {
+        V del = (k2.o - k1.o).unit().turn90().getdel();
+        return {
+            (line){k1.o - del * k1.r, k2.o - del * k2.r},
+            (line){k1.o + del * k1.r, k2.o + del * k2.r}
+        };
+    } else {
+        V p = (k2.o * k1.r - k1.o * k2.r) / (k1.r - k2.r);
+        vector<V> A = TangentCP(k1, p), B = TangentCP(k2, p);
+        vector<line> ans;
+        for (int i = 0; i < A.size(); i++) ans.push_back((line){A[i], B[i]});
+        return ans;
+    }
+}
+vector<line> TangentinCC(circle k1, circle k2) {
+    int pd = checkposCC(k1, k2);
+    if (pd <= 2) return {};
+    if (pd == 3) {
+        V k = getCC(k1, k2)[0];
+        return { (line){k, k} };
+    }
+    V p = (k2.o * k1.r + k1.o * k2.r) / (k1.r + k2.r);
+    vector<V> A = TangentCP(k1, p), B = TangentCP(k2, p);
+    vector<line> ans;
+    for (int i = 0; i < A.size(); i++) ans.push_back((line){A[i], B[i]});
+    return ans;
+}
+vector<line> TangentCC(circle k1, circle k2) {
+    int flag = 0;
+    if (k1.r < k2.r) swap(k1, k2), flag = 1;
+    vector<line> A = TangentoutCC(k1, k2), B = TangentinCC(k1, k2);
+    for (line k: B) A.push_back(k);
+    if (flag) for (line& k: A) swap(k[0], k[1]);
+    return A;
+}
+ld convexDiameter(vector<V> A) {
+    int now = 0, n = A.size();
+    ld ans = 0;
+    for (int i = 0; i < A.size(); i++) {
+        now = max(now, i);
+        while (1) {
+            ld k1 = A[i].dis(A[now % n]), k2 = A[i].dis(A[(now + 1) % n]);
+            ans = max(ans, max(k1, k2));
+            if (k2 > k1) now++;
+            else break;
+        }
+    }
+    return ans;
+}
+vector<V> convexcut(vector<V> A, V k1, V k2) { // 保留 k1,k2,p 逆时针的所有点
+    int n = A.size();
+    A.push_back(A[0]);
+    vector<V> ans;
+    for (int i = 0; i < n; i++) {
+        int w1 = clockwise(k1, k2, A[i]), w2 = clockwise(k1, k2, A[i + 1]);
+        if (w1 >= 0) ans.push_back(A[i]);
+        if (w1 * w2 < 0) ans.push_back(getLL(k1, k2, A[i], A[i + 1]));
+    }
+    return ans;
+}
+```
+
+### 本模板未涉及的专题
+
++ ECNU
+
+**数据结构**
+
+均摊复杂度线段树 K-DTree 树状数组套主席树 左偏树 Treap-序列 可回滚并查集 舞蹈链 笛卡尔树 莫队
+
+**数学**
+
+min_25 杜教筛 伯努利数和等幂求和 单纯形 数论分块
+
+**图论**
+
+zkw费用流 树上点分治 二分图匹配 虚树 欧拉路径 一般图匹配 点双连通分量/广义圆方树
+圆方树 最小树形图 三元环、四元环
+
+**计算几何**
+
+圆与多边形交 圆的离散化、面积并 圆的反演 三维计算几何 旋转 线、面 凸包
+
++ kuangbin
+
+**数学**
+
+整数拆分 求A^B的约数之和对MOD取模 斐波那契数列取模循环节
+
+**图论**
+
+次小生成树 生成树计数 曼哈顿最小生成树
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4f0b7b7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Yiyuan Luo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..dcbda0d
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# qdd-s-ICPC-template
-- 
GitLab