---
# System prepended metadata

title: NOTEBOOK ICPC No_Zone_for_Loser

---

**ICPC NOTEBOOK**

**School : Le Hong Phong High School for The Gifted**
**Team : No_Zone_for_Loser**
**Member : Nguyễn Tấn Minh (11CTIN-A), Đặng Thành Nghĩa (11CTIN-A), Lê Lâm (10CTIN)**

[TOC]
# Main template

```cpp!
#include<bits/stdc++.h>

using namespace std;

#define range(v) begin(v), end(v)
#define compact(v) v.erase(unique(range(v)), end(v))
#define len(x) (int)(x).size()
#define BIT(x, i) ((x)>>(i)&1)
#define MASK(x) (1LL<<(x))
#define forw(i,j,z) for(int i=(int)j;i<=(int)z;i++)
#define ford(i,j,z) for(int i=(int)j;i>=(int)z;i--)
#define mp make_pair
//define lucian nghiaaa's cuties
//define zero_op nghiaaa's cuties
//define No_Zone_for_Loser winner team 

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;

template<class T> bool maximize(T& a, const T& b){ if(a<b) return a=b, true; return false; }
template<class T> bool minimize(T& a, const T& b){ if(a>b) return a=b, true; return false; }

void No_Zone_for_Loser(){

}

signed main(){
  ios_base::sync_with_stdio(0);
  cin.tie(NULL); cout.tie(NULL);

  #define task "a"
  if(fopen(task".inp", "r")){
    freopen(task".inp", "r", stdin);
    freopen(task".out", "w", stdout);
  }

  int TC=1; //cin>>TC;
  while(TC--) No_Zone_for_Loser();

  return 0;
}

```

# MATH

## Miller Rabin
```cpp!
// From https://github.com/SnapDragon64/ContestLibrary/blob/master/math.h
// which also has specialized versions for 32-bit and 42-bit
//
// Tested:
// - https://oj.vnoi.info/problem/icpc22_national_c (fastest solution)
// - https://www.spoj.com/problems/PON/

// Rabin miller {{{
inline uint64_t mod_mult64(uint64_t a, uint64_t b, uint64_t m) {
    return __int128_t(a) * b % m;
}
uint64_t mod_pow64(uint64_t a, uint64_t b, uint64_t m) {
    uint64_t ret = (m > 1);
    for (;;) {
        if (b & 1) ret = mod_mult64(ret, a, m);
        if (!(b >>= 1)) return ret;
        a = mod_mult64(a, a, m);
    }
}

// Works for all primes p < 2^64
bool is_prime(uint64_t n) {
    if (n <= 3) return (n >= 2);
    static const uint64_t small[] = {
        2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
        71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139,
        149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
    };
    for (size_t i = 0; i < sizeof(small) / sizeof(uint64_t); ++i) {
        if (n % small[i] == 0) return n == small[i];
    }

    // Makes use of the known bounds for Miller-Rabin pseudoprimes.
    static const uint64_t millerrabin[] = {
        2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
    };
    static const uint64_t A014233[] = {  // From OEIS.
        2047LL, 1373653LL, 25326001LL, 3215031751LL, 2152302898747LL,
        3474749660383LL, 341550071728321LL, 341550071728321LL,
        3825123056546413051LL, 3825123056546413051LL, 3825123056546413051LL, 0,
    };
    uint64_t s = n-1, r = 0;
    while (s % 2 == 0) {
        s /= 2;
        r++;
    }
    for (size_t i = 0, j; i < sizeof(millerrabin) / sizeof(uint64_t); i++) {
        uint64_t md = mod_pow64(millerrabin[i], s, n);
        if (md != 1) {
            for (j = 1; j < r; j++) {
                if (md == n-1) break;
                md = mod_mult64(md, md, n);
            }
            if (md != n-1) return false;
        }
        if (n < A014233[i]) return true;
    }
    return true;
}
// }}}
```
## FFT
```cpp!
using cd=complex<double>;
const double PI=acos(-1);

void fft(vector<cd>& a, bool is_inverse){
    int n=a.size();
    int lg=0; while((1<<lg)<n) ++lg;

    for(int i=1, j=0; i<n; ++i){
        int bit=n>>1;
        for(; j&bit; bit>>=1) j^=bit;
        j^=bit;
        if(i<j) swap(a[i], a[j]);
    }

    for(int len=2; len<=n; len<<=1){
        double ang=2.0*PI/len*(is_inverse?-1:1);
        cd wlen(cos(ang), sin(ang));
        for(int i=0; i<n; i+=len){
            cd w(1);
            for(int j=0; j*2<len; ++j){
                cd u=a[i+j], v=a[i+j+len/2]*w;
                a[i+j]=u+v;
                a[i+j+len/2]=u-v;
                w*=wlen;
            }
        }
    }
    if(is_inverse){
        for(cd &x:a) x/=n;
    }
}

vector<int> multiply(const vector<int>& a, const vector<int>& b){
    vector<cd> fa(all(a)), fb(all(b));
    int n=1; while(a.size()+b.size()>n) n<<=1;

    fa.resize(n), fb.resize(n);
    fft(fa, 0), fft(fb, 0);
    for(int i=0; i<n; ++i) fa[i]*=fb[i];
    fft(fa, 1);

    vector<int> result(n);
    for(int i=0; i<n; ++i) result[i]=round(fa[i].real());
    return result;
}
```

## NTT
```cpp!
// NTT {{{
//
// Faster than NTT_chemthan.h
//
// Usage:
// auto c = multiply(a, b);
// where a and b are vector<ModInt<ANY_MOD>>
// (If mod is NOT NTT_PRIMES, it does 3 NTT and combine result)

constexpr int NTT_PRIMES[] = {998244353, 167772161, 469762049};

// assumptions:
// - |a| is power of 2
// - mint::mod() is a valid NTT primes (2^k * m + 1)
template<typename mint> void ntt(std::vector<mint>& a, bool is_inverse) {
    int n = a.size();
    if (n == 1) return;

    static const int mod = mint::mod();
    static const mint root = mint::get_primitive_root();
    assert(__builtin_popcount(n) == 1 && (mod - 1) % n == 0);

    static std::vector<mint> w{1}, iw{1};
    for (int m = w.size(); m < n / 2; m *= 2) {
        mint dw = root.pow((mod - 1) / (4 * m));
        mint dwinv = dw.inv();
        w.resize(m * 2);
        iw.resize(m * 2);
        for (int i = 0; i < m; ++i) {
            w[m + i] = w[i] * dw;
            iw[m + i] = iw[i] * dwinv;
        }
    }

    if (!is_inverse) {
        for (int m = n; m >>= 1; ) {
            for (int s = 0, k = 0; s < n; s += 2 * m, ++k) {
                for (int i = s; i < s + m; ++i) {
                    mint x = a[i], y = a[i + m] * w[k];
                    a[i] = x + y;
                    a[i + m] = x - y;
                }
            }
        }
    } else {
        for (int m = 1; m < n; m *= 2) {
            for (int s = 0, k = 0; s < n; s += 2 * m, ++k) {
                for (int i = s; i < s + m; ++i) {
                    mint x = a[i], y = a[i + m];
                    a[i] = x + y;
                    a[i + m] = (x - y) * iw[k];
                }
            }
        }
        int n_inv = mint(n).inv().x;
        for (auto& v : a) v *= n_inv;
    }
}

template<typename mint>
std::vector<mint> ntt_multiply(int sz, std::vector<mint> a, std::vector<mint> b) {
    a.resize(sz);
    b.resize(sz);
    if (a == b) { // optimization for squaring polynomial
        ntt(a, false);
        b = a;
    } else {
        ntt(a, false);
        ntt(b, false);
    }
    for (int i = 0; i < sz; ++i) a[i] *= b[i];
    ntt(a, true);
    return a;
}

template<int MOD, typename mint>
std::vector<ModInt<MOD>> convert_mint_and_multiply(
        int sz,
        const std::vector<mint>& a,
        const std::vector<mint>& b) {
    using mint2 = ModInt<MOD>;

    std::vector<mint2> a2(a.size()), b2(b.size());
    for (size_t i = 0; i < a.size(); ++i) {
        a2[i] = mint2(a[i].x);
    }
    for (size_t i = 0; i < b.size(); ++i) {
        b2[i] = mint2(b[i].x);
    }
    return ntt_multiply(sz, a2, b2);
}

long long combine(int r0, int r1, int r2, int mod) {
    using mint2 = ModInt<NTT_PRIMES[2]>;
    static const long long m01 = 1LL * NTT_PRIMES[0] * NTT_PRIMES[1];
    static const long long m0_inv_m1 = ModInt<NTT_PRIMES[1]>(NTT_PRIMES[0]).inv().x;
    static const long long m01_inv_m2 = mint2(m01).inv().x;

    int v1 = (m0_inv_m1 * (r1 + NTT_PRIMES[1] - r0)) % NTT_PRIMES[1];
    auto v2 = (mint2(r2) - r0 - mint2(NTT_PRIMES[0]) * v1) * m01_inv_m2;
    return (r0 + 1LL * NTT_PRIMES[0] * v1 + m01 % mod * v2.x) % mod;
}

template<typename mint>
std::vector<mint> multiply(const std::vector<mint>& a, const std::vector<mint>& b) {
    if (a.empty() || b.empty()) return {};
    int sz = 1, sz_a = a.size(), sz_b = b.size();
    while (sz < sz_a + sz_b) sz <<= 1;
    if (sz <= 16) {
        std::vector<mint> res(sz_a + sz_b - 1);
        for (int i = 0; i < sz_a; ++i) {
            for (int j = 0; j < sz_b; ++j) {
                res[i + j] += a[i] * b[j];
            }
        }
        return res;
    }

    int mod = mint::mod();
    std::vector<mint> res;
    if (std::find(std::begin(NTT_PRIMES), std::end(NTT_PRIMES), mod) != std::end(NTT_PRIMES)) {
        res = ntt_multiply(sz, a, b);
    } else {
        auto c0 = convert_mint_and_multiply<NTT_PRIMES[0], mint> (sz, a, b);
        auto c1 = convert_mint_and_multiply<NTT_PRIMES[1], mint> (sz, a, b);
        auto c2 = convert_mint_and_multiply<NTT_PRIMES[2], mint> (sz, a, b);

        res.resize(sz);
        for (int i = 0; i < sz; ++i) {
            res[i] = combine(c0[i].x, c1[i].x, c2[i].x, mod);
        }
    }

    res.resize(sz_a + sz_b - 1);
    return res;
}
// }}}
```

## Lucas Theorem
```cpp!
//Calculate C(n, k) modulo M with smal M and big n, k
const int M=1e5+3;

int sub(int a, int b){ return (a<b?a-b+M:a-b); }
int add(int a, int b){ return (a+b<M?a+b:a+b-M); }
int mul(int a, int b){ return 1LL*a*b%M; }
int binpow(int a, int b){ int ans=1; while(b){ if(b&1) ans=mul(ans, a); a=mul(a, a); b>>=1; } return ans; }
int inverse(int a){ return binpow(a, M-2); }

int fact[M], inv[M];

int C(int NN, int KK){
  if(NN<KK) return 0;
  return mul(fact[NN], mul(inv[KK], inv[NN-KK]));
}

int Lucas(ll n, ll m){
  if(n<m) return 0;

  int ans=1;
  for(int i=0; i<4; ++i){
    int mod_n=n%M, mod_m=m%M;
    n/=M; m/=M;
    ans=mul(ans, C(mod_n, mod_m));
  }
  return ans;
}
```

# DP Trick

## Line Container
```cpp!
struct Line {
  mutable ll m, b, p;
  bool operator<(const Line& o) const { return m < o.m; }
  bool operator<(ll x) const { return p < x; }
};
 
struct LineContainer : multiset<Line, less<>> {
  // (for doubles, use inf = 1/.0, div(a,b) = a/b)
  // Caution : This template solve for finding MAX, so if want to find MIN, NEGATE ALL THE LINE FUNCTION
    const ll inf = LLONG_MAX;
  ll div(ll a, ll b) { // floored division
    return a/b-((a^b)<0&&a%b); }
  bool isect(iterator x, iterator y) {
    if (y==end()) { x->p=inf; return false; }
    if (x->m==y->m) x->p=x->b>y->b?inf:-inf;
    else x->p=div(y->b-x->b, x->m-y->m);
    return x->p>=y->p;
  }
  void add(ll m, ll b) {
    auto z=insert({m, b, 0}), y=z++, x=y;
    while(isect(y, z)) z=erase(z);
    if (x!=begin() && isect(--x, y)) isect(x, y = erase(y));
    while((y = x)!=begin() && (--x)->p>=y->p)
    isect(x, erase(y));
  }
  ll query(ll x) { // max value at x
    assert(!empty());
    auto l=*lower_bound(x);
    return l.m*x+l.b;
  }
};
```

# GRAPH

## Gomory Hu
```cpp!
// Usage:
//   GomoryHu g(n);
//   g.addEdge(u, v, c)  // 1-direction
//   g.calc()
//   --> g.answer[i][j] = min cut i-j
//
// Note:
// - When i -> j is not connected, answer[i][j] = INF
// - Used together with MaxFlowDinic.h
//
// Tested:
// - https://oj.vnoi.info/problem/mcquery
// - https://oj.vnoi.info/problem/icpc21_mn_a

/*
 * Find min cut between every pair of vertices using N max_flow call (instead of N^2)
 * Not tested with directed graph
 * Index start from 0
 */
struct GomoryHu {
    int ok[MN], cap[MN][MN];
    int answer[MN][MN], parent[MN];
    int n;
    MaxFlow flow;

    GomoryHu(int _n) : n(_n), flow(_n) {
        for(int i = 0; i < n; ++i) ok[i] = parent[i] = 0;
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n; ++j)
                cap[i][j] = 0, answer[i][j] = INF;
    }

    void addEdge(int u, int v, int c) {
        cap[u][v] += c;
    }

    void calc() {
        for(int i = 1; i <= n-1; ++i) {
            flow = MaxFlow(n);
            REP(u,n) REP(v,n)
                if (cap[u][v])
                    flow.addEdge(u, v, cap[u][v]);

            int f = flow.getMaxFlow(i, parent[i]);

            bfs(i);
            for(int j = i+1; j < n; ++j)
                if (ok[j] && parent[j]==parent[i])
                    parent[j]=i;
            
            answer[i][parent[i]] = answer[parent[i]][i] = f;
            for(int j = 0; j < i; ++j)
                answer[i][j]=answer[j][i]=min(f,answer[parent[i]][j]);
        }
    }
    void bfs(int start) {
        memset(ok,0,sizeof ok);
        queue<int> qu;
        qu.push(start);
        while (!qu.empty()) {
            int u=qu.front(); qu.pop();
            for(int xid = 0; xid < (int) flow.g[u].size(); ++xid) {
                int id = flow.g[u][xid];
                int v = flow.e[id].b, fl = flow.e[id].flow, c = flow.e[id].cap;
                if (!ok[v] && fl < cap) {
                    ok[v]=1;
                    qu.push(v);
                }
            }
        }
    }
};
```

# DATA STRUCTURE

## Manhattan MST
```cpp!
struct Point{
  int x, y, id;
  Point(int x=0, int y=0, int id=0):x(x), y(y), id(id){}
};

struct Edge{
  int u, v, w;
  Edge(int u=0, int v=0, int w=0):u(u), v(v), w(w){}
  bool operator<(const Edge& other) const{
    return w<other.w;
  }
};

int n, lab[N], ID[N], EDGE_SZ;
Point P[N];
Edge E[N*4];

int root(int u){ return (lab[u]<0?u:(lab[u]=root(lab[u]))); }
bool unite(int u, int v){
   u=root(u), v=root(v); if(u==v) return false;
   if(lab[u]>lab[v]) swap(u, v); lab[u]+=lab[v]; lab[v]=u; return true;
}

void get_edge(){
  map<int, int> M;
  iota(ID+1, ID+1+n, 1);
  sort(ID+1, ID+1+n, [&](int u, int v){
    return (P[u].x+P[u].y)<(P[v].x+P[v].y);
  });
  for(int T=1, i; T<=n; ++T){
    i=ID[T];
    for(auto iter=M.lower_bound(-P[i].x); iter!=M.end(); M.erase(iter++)){
      if((P[iter->second].y-P[i].y)>(P[iter->second].x-P[i].x)) break;
      E[EDGE_SZ++]=Edge(iter->second, i, P[i].y-P[iter->second].y+P[i].x-P[iter->second].x);
    }
    M[-P[i].x]=i;
  }
}

void solve(){
  cin>>n;
  for(int i=1; i<=n; ++i){
    cin>>P[i].x>>P[i].y;
    P[i].id=i;
  }
  fill(lab+1, lab+1+n, -1);

  for(int d=0; d<4; ++d){
    get_edge();
    for(int i=1; i<=n; ++i){
      if(d&1) P[i].x*=-1;
      else swap(P[i].x, P[i].y);
    }
  }

  sort(E, E+EDGE_SZ);
  ll ans=0; vector<pair<int, int>> pairs;
  for(int i=0; i<EDGE_SZ; ++i){
    if(unite(E[i].u, E[i].v)){
      ans+=E[i].w;
      pairs.push_back({E[i].u-1, E[i].v-1});
    }
  }
  cout<<ans<<ln;
  for(auto [u, v]:pairs) cout<<u<<" "<<v<<ln;
}
```

## Wavelet Tree
```cpp!
// WaveletMatrix {{{
// Copied from https://github.com/dacin21/dacin21_codebook/blob/master/trees/wavelet_matrix.cpp
//
// Notes:
// - Index from 0
// - k (for k-th query) from 0
// - Need to remove #define int long long
//
// Tested:
// - (kth query) https://judge.yosupo.jp/problem/range_kth_smallest
// - (range_count) https://judge.yosupo.jp/problem/static_range_frequency
class Bit_Presum{
public:
    static constexpr uint32_t omega = CHAR_BIT * sizeof(uint64_t);
    static constexpr uint32_t lg_omega = __lg(omega);
    static_assert(omega == 64u);

    Bit_Presum(vector<uint64_t> mask_) : n(mask_.size()), mask(move(mask_)), presum(n+1){
        build();
    }
    Bit_Presum(uint32_t bits, bool init_val = 0) : n((bits>>lg_omega) + 1), mask(n, init_val ? ~uint64_t{0} : uint64_t{0}), presum(n+1){
        if(init_val) mask.back()<<=((n<<lg_omega) - bits);
        build();
    }
    /// popcount l <= i < r
    uint32_t query(uint32_t l, uint32_t r) const {
        if(__builtin_expect(r < l, false)) return 0;
        return query(r) - query(l);
    }
    /// popcount 0 <= i < x
    uint32_t query(uint32_t x) const {
        uint32_t high = x>>lg_omega, low = x & ((uint64_t{1}<<lg_omega) - 1);
        uint32_t ret = presum_query(high);
        ret+= __builtin_popcountll(mask[high]& ((uint64_t{1} << low)-1));
        return ret;
    }

    void update_pre_build(uint32_t x, bool val){
        uint32_t high = x>>lg_omega, low = x & ((1u<<lg_omega) - 1);
        mask[high] = (mask[high] & ~(uint64_t{1} << low)) | (uint64_t{val}<<low);
    }
    void do_build(){
        build();
    }

    friend ostream& operator<<(ostream&o, Bit_Presum const&b){
        for(auto const&e:b.mask){
            stringstream ss;
            ss << bitset<omega>(e);
            auto s = ss.str();
            reverse(s.begin(), s.end());
            o << s << "|";
        }
        o << " : ";
        for(auto const&e:b.presum) o << e << " ";
        o << "\n";
        return o;
    }

private:
    void presum_build(){
        for(uint32_t x=1;x<=n;++x){
            presum[x]+=presum[x-1];
        }
    }
    // sum 0 <= i < x
    uint32_t presum_query(uint32_t x) const {
        return presum[x];
    }
    void build(){
        for(uint32_t x=0;x<n;++x){
            presum[x+1] = __builtin_popcountll(mask[x]);
        }
        presum_build();
    }

    const uint32_t n;
    vector<uint64_t> mask;
    vector<uint32_t> presum;
};

template<typename T, typename Bit_Ds = Bit_Presum>
class WaveletMatrix{
public:
    static_assert(is_integral<T>::value);
    static constexpr uint32_t height = CHAR_BIT * sizeof(T);

    WaveletMatrix(vector<T> v): n(v.size()), data(height, n){
        build(move(v));
    }
    /// count l <= i < r  s.t.  A <= val[i] < B
    uint32_t range_count(int const&l, int const&r, T const&A, T const&B) const {
        assert(0 <= l && r <= n);
        return count_lower(l, r, B) - count_lower(l, r, A);
    }
    /// count l <= i < r  s.t.  A <= val[i]
    uint32_t range_count_up(int const&l, int const&r, T const&A) const {
        assert(0 <= l && r <= n);
        if(__builtin_expect(l>r, false)) return uint32_t{0};
        return (r-l) - count_lower(l, r, A);
    }
    // k from 0
    T k_th(int const&l, int const&r, int k) const {
        assert(0 <= k && k < n);
        return get_kth(l, r, k);
    }

private:
    void build(vector<T> v){
        m_index.resize(height);
        T const a = numeric_limits<T>::min();
        for(int h = height-1; h>=0;--h){
            T const b = a + (T{1}<<(max(0, h-1))) - !h + (T{1}<<(max(0, h-1)));
            for(int i=0;i<n;++i){
                data[h].update_pre_build(i, v[i]<b);
            }
            data[h].do_build();
            const int m = stable_partition(v.begin(), v.end(), [&b](T const&x){return x < b;}) - v.begin();
            for(int i=m;i<n;++i){
                v[i] = v[i] - (T{1}<<(max(0, h-1))) + !h - (T{1}<<(max(0, h-1)));
            }
            m_index[h] = m;
        }
    }
    /// count l <= i < r  s.t.  val[i] < B
    uint32_t count_lower(int l, int r, T const&B) const {
        assert(0 <= l && r <= n);
        if(__builtin_expect(r<l, false)) return 0;
        uint32_t ret = 0;
        int h = height;
        T a = numeric_limits<T>::min();
        while(h > 0){
            --h;
			bool go_left = B < a + (T{1}<<(max(0, h-1))) - !h + (T{1}<<(max(0, h-1)));
            const int low_l = data[h].query(l), low_r = data[h].query(r);
            if(go_left){
                l = low_l;
                r = low_r;
            } else {
                a = a + (T{1}<<(max(0, h-1))) - !h + (T{1}<<(max(0, h-1)));
                ret+= low_r-low_l;
                l = m_index[h] + l-low_l;
                r = m_index[h] + r-low_r;
            }
        }
        return ret;
    }
    T get_kth(int l, int r, int k) const {
        assert(0 <= l && r <= n);
        assert(0 <= k && k < r-l);
        int h = height;
        T a = numeric_limits<T>::min();
        while(h > 0){
            --h;
            const int low_l = data[h].query(l), low_r = data[h].query(r), low_lr = low_r-low_l;
            bool go_left = k < low_lr;
            if(go_left){
                l = low_l;
                r = low_r;
            } else {
                a+= T{1}<<h;
                k-= low_lr;
                l = m_index[h] + l-low_l;
                r = m_index[h] + r-low_r;
            }
        }
        return a;
    }

    const int n;
    vector<int> m_index;
    vector<Bit_Ds> data;
};
// }}}
```

## Partially Persistent DSU
```cpp!
struct PersistentDSU{
  vector<int> lab, time_united;
  PersistentDSU(int n):lab(n, -1), time_united(n, INF32){}
 
  int root(int u, int ver){
    if(time_united[u]>ver) return u;
    else return root(lab[u], ver);
  }
 
  void unite(int u, int v, int ver){
    u=root(u, ver), v=root(v, ver);
    if(u!=v){
      if(lab[u]>lab[v]) swap(u, v);
      lab[u]+=lab[v]; lab[v]=u; time_united[v]=ver;
    }
  }
 
  bool same_set(int u, int v, int ver){
    return root(u, ver)==root(v, ver);
  }
```

# STRING 

## Update Hash
```cpp!
struct hash_BIT {
    vector<ll> tr, base;
    ll MOD;

    hash_BIT (int n) : tr(n + 1, 0) {
        MOD = 1e9 + 21;
        base.resize(n + 1);
        base[0] = 1;
        for (int i = 1; i <= n; i++) base[i] = base[i-1] * 29LL % MOD;
        return;
    }

private:
    int p (int k) {
        return k & -k;
    }

    ll pre (int k) {
        ll ans = 0;
        for (int j = k; j > 0; j -= p(j))
            ans = (ans + tr[j] * base[k - j]) % MOD;
        return ans;
    }

public:
    ll get_hash (int l, int r) {
        if (l > r) return 0;
        return (pre(r) - pre(l - 1) * base[r - l + 1] + MOD * MOD) % MOD;
    }

    void update (int k, char c) {
        ll delta = c - 'a' + 1 - get_hash(k, k);
        for (int j = k; j < tr.size(); j += p(j))
            tr[j] = (tr[j] + delta * base[j - k] + MOD * MOD) % MOD;
        return;
    }

    void append (char c) {
        int pos = tr.size();
        tr.push_back((get_hash(pos - p(pos) + 1, pos - 1) * 29LL + c - 'a' + 1) % MOD);
        return;
    }
};
```

## Manacher

```cpp!
string t; cin >> t;
vector<char> s;
s.push_back('.');
for(char d : t){
    s.push_back(d);
    s.push_back('.');
}
int n = s.size();
vi best(n); // longest palindrome centered at i
int center = 0, lst = 0;
for(int i = 1; i < n; ++i){
    if(lst > i)
    best[i] = min(best[center - (i - center)], lst - i);
    int l = i - best[i], r = i + best[i];
    while(l - 1 >= 0 && r + 1 < n && s[l - 1] == s[r + 1]){
        --l, ++r;
        ++best[i];
    }
    if(i + best[i] > lst){
        lst = i + best[i];
        center = i;
    }
}
ll ans = 0;
for(int i = 0; i < n; ++i){
    best[i] = best[i] * 2 + 1;
    if(s[i] == '.') ans += (best[i] - 1) / 4;
    else ans += (best[i] + 1) / 4;
}
cout << ans;
```

## Z-function

```cpp!
void z_func(string s, int n){
  vector<int> z(n);
	for(int l = 0, r = 0, i = 1; i < n; ++i){
        if(i <= r) z[i] = min(z[i - l], r - i + 1);
        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;
        }
    }
}
```

## Suffix Array
```cpp!
// Efficient O(N + alphabet_size) time and space suffix array
// For ICPC notebook, it's better to copy a shorter code such as
// https://github.com/kth-competitive-programming/kactl/blob/main/content/strings/SuffixArray.h

// Usage:
// - sa = suffix_array(s, 'a', 'z')
// - lcp = LCP(s, sa)
//   lcp[i] = LCP(sa[i], sa[i+1])
//
// Tested:
// - SA https://judge.yosupo.jp/problem/suffixarray
// - SA https://www.spoj.com/problems/SARRAY/
// - LCP https://judge.yosupo.jp/problem/number_of_substrings
// Suffix Array {{{
// Copied from https://judge.yosupo.jp/submission/52300
// Helper functions {{{
void induced_sort(const std::vector<int>& vec, int val_range,
                  std::vector<int>& SA, const std::vector<bool>& sl,
                  const std::vector<int>& lms_idx) {
    std::vector<int> l(val_range, 0), r(val_range, 0);
    for (int c : vec) {
        if (c + 1 < val_range) ++l[c + 1];
        ++r[c];
    }
    std::partial_sum(l.begin(), l.end(), l.begin());
    std::partial_sum(r.begin(), r.end(), r.begin());
    std::fill(SA.begin(), SA.end(), -1);
    for (int i = (int)lms_idx.size() - 1; i >= 0; --i)
        SA[--r[vec[lms_idx[i]]]] = lms_idx[i];
    for (int i : SA)
        if (i >= 1 && sl[i - 1]) SA[l[vec[i - 1]]++] = i - 1;
    std::fill(r.begin(), r.end(), 0);
    for (int c : vec) ++r[c];
    std::partial_sum(r.begin(), r.end(), r.begin());
    for (int k = (int)SA.size() - 1, i = SA[k]; k >= 1; --k, i = SA[k])
        if (i >= 1 && !sl[i - 1]) {
            SA[--r[vec[i - 1]]] = i - 1;
        }
}

std::vector<int> SA_IS(const std::vector<int>& vec, int val_range) {
    const int n = vec.size();
    std::vector<int> SA(n), lms_idx;
    std::vector<bool> sl(n);
    sl[n - 1] = false;
    for (int i = n - 2; i >= 0; --i) {
        sl[i] = (vec[i] > vec[i + 1] || (vec[i] == vec[i + 1] && sl[i + 1]));
        if (sl[i] && !sl[i + 1]) lms_idx.push_back(i + 1);
    }
    std::reverse(lms_idx.begin(), lms_idx.end());
    induced_sort(vec, val_range, SA, sl, lms_idx);
    std::vector<int> new_lms_idx(lms_idx.size()), lms_vec(lms_idx.size());
    for (int i = 0, k = 0; i < n; ++i)
        if (!sl[SA[i]] && SA[i] >= 1 && sl[SA[i] - 1]) {
            new_lms_idx[k++] = SA[i];
        }
    int cur = 0;
    SA[n - 1] = cur;
    for (size_t k = 1; k < new_lms_idx.size(); ++k) {
        int i = new_lms_idx[k - 1], j = new_lms_idx[k];
        if (vec[i] != vec[j]) {
            SA[j] = ++cur;
            continue;
        }
        bool flag = false;
        for (int a = i + 1, b = j + 1;; ++a, ++b) {
            if (vec[a] != vec[b]) {
                flag = true;
                break;
            }
            if ((!sl[a] && sl[a - 1]) || (!sl[b] && sl[b - 1])) {
                flag = !((!sl[a] && sl[a - 1]) && (!sl[b] && sl[b - 1]));
                break;
            }
        }
        SA[j] = (flag ? ++cur : cur);
    }
    for (size_t i = 0; i < lms_idx.size(); ++i) lms_vec[i] = SA[lms_idx[i]];
    if (cur + 1 < (int)lms_idx.size()) {
        auto lms_SA = SA_IS(lms_vec, cur + 1);
        for (size_t i = 0; i < lms_idx.size(); ++i) {
            new_lms_idx[i] = lms_idx[lms_SA[i]];
        }
    }
    induced_sort(vec, val_range, SA, sl, new_lms_idx);
    return SA;
}
// }}}

template<typename ContainerT = std::string, typename ElemT = unsigned char>
std::vector<int> suffix_array(const ContainerT& s, const ElemT first = 'a',
                         const ElemT last = 'z') {
    std::vector<int> vec(s.size() + 1);
    std::copy(std::begin(s), std::end(s), std::begin(vec));
    for (auto& x : vec) x -= (int)first - 1;
    vec.back() = 0;
    auto ret = SA_IS(vec, (int)last - (int)first + 2);
    ret.erase(ret.begin());
    return ret;
}

std::vector<int> LCP(const std::string& s, const std::vector<int>& sa) {
    int n = s.size(), k = 0;
    std::vector<int> lcp(n), rank(n);
    for (int i = 0; i < n; i++) rank[sa[i]] = i;
    for (int i = 0; i < n; i++, k ? k-- : 0) {
        if (rank[i] == n - 1) {
            k = 0;
            continue;
        }
        int j = sa[rank[i] + 1];
        while (i + k < n && j + k < n && s[i + k] == s[j + k]) k++;
        lcp[rank[i]] = k;
    }
    lcp[n - 1] = 0;
    return lcp;
}

int64_t cnt_distinct_substrings(const std::string& s) {
    auto lcp = LCP(s, suffix_array(s, 0, 255));
    return s.size() * (int64_t) (s.size() + 1) / 2
        - std::accumulate(lcp.begin(), lcp.end(), 0LL);
}
```

## Prefix Function

```cpp!
vector<int> prefixFunc (string s) {
    int n = s.length();
    vector<int> pi(n);
    for (int i = 1; i < n; i++) {
        int j = pi[i - 1];
        while (j && s[j] != s[i]) j = pi[j - 1];
        if (s[j] == s[i]) pi[i] = j + 1;
    }
    return pi;
}
```

# GEO

## Basic
```cpp!
template<class T> struct Point{
  T x, y;
  Point(T _x=0, T _y=0):x(_x), y(_y){}

  template<class U> operator Point<U>(){
    return Point<U>(U(x), U(y));
  }

  Point &operator+=(Point p){
    x+=p.x; y+=p.y;
    return *this;
  }

  Point &operator-=(Point p){
    x-=p.x; y-=p.y;
    return *this;
  }

  Point &operator*=(T v){
    x*=v; y*=v;
    return *this;
  }

  Point &operator/=(T v){
    x/=v; y/=v;
    return *this;
  }

  Point operator-() const{
    return Point(-x, -y);
  }

  friend Point operator+(Point a, Point b){
    return a+=b;
  }

  friend Point operator-(Point a, Point b){
    return a-=b;
  }

  friend Point operator*(Point a, T v){
    return a*=v;
  }

  friend Point operator*(T v, Point a){
    return a*=v;
  }

  friend Point operator/(Point a, T v){
    return a/=v;
  }

  friend bool operator==(Point a, Point b){
    return a.x==b.x and a.y==b.y;
  }

  friend istream& operator>>(istream& in, Point& p){
    return in>>p.x>>p.y;
  }

  friend ostream& operator<<(ostream& out, Point p){
    return out<<p.x<<' '<<p.y;
  }
};

template<class T> T dot(Point<T> a, Point<T> b){
  return a.x*b.x+a.y*b.y;
}

template<class T> T cross(Point<T> a, Point<T> b){
  return a.x*b.y-a.y*b.x;
}

template<class T> T dot(Point<T> a, Point<T> b, Point<T> c){
  return dot(b-a, c-a);
}

template<class T> T cross(Point<T> a, Point<T> b, Point<T> c){
  return cross(b-a, c-a);
}

template<class T> T square(Point<T> a){
  return dot(a, a);
}

template<class T> double length(Point<T> p){
  return sqrt(square(p));
}

long double length(Point<long double> p){
  return sqrt(square(p));
}

template<class T> Point<T> normalize(Point<T> p){
  return p/length(p);
}

template<class T> T manhattan(Point<T> a, Point<T> b){
  return abs(a.x-b.x)+abs(a.y-b.y);
}

template<class T> int sign(T x){
  return (x==0?0:(x<0?-1:1));
}

//segment AB, point C
template<class T> bool onSegment(Point<T> a, Point<T> b, Point<T> c){
  return cross(a-c, b-c)==0 and dot(a-c, b-c)<=0;
}

//segment AB, CD
template<class T> bool intersect(Point<T> a, Point<T> b, Point<T> c, Point<T> d){
  return onSegment(a, b, c) or onSegment(a, b, d) or onSegment(c, d, a) or onSegment(c, d, b) or
  (sign(cross(a, b, c))*sign(cross(a, b, d))<0 and sign(cross(c, d, a))*sign(cross(c, d, b))<0);
}

using point=Point<long long>;

template<class T> struct Line{
  T a, b, c; //ax+by+c=0
  Line(Point<T> A, Point<T> B){
    a=B.y-A.y;
    b=A.x-B.x;
    c=-A.x*B.y+A.y*B.x;
  }
  Line(T _a=0, T _b=0, T _c=0){
    a=_a, b=_b, c=_c;
  }
  T func(T x, T y){
    return a*x+b*y+c;
  }
  friend istream& operator>>(istream& in, Line& d){
    return in>>d.a>>d.b>>d.c;
  }
};

//line AB, point C
template<class T> long double LineToPoint(Point<T> a, Point<T> b, Point<T> c){
  return abs(cross(a, b, c))/length(a-b);
}

//line AB, point C
template<class T> long double LineToPoint(Line<T> d, Point<T> p){
  return abs(d.func(p.x, p.y))/sqrt(d.a*d.a+d.b*d.b);
}

using line=Line<long long>;

//line AB, CD
template<class T> bool parallel(Point<T> a, Point<T> b, Point<T> c, Point<T> d){
  Line<T> d1(a, b), d2(c, d);
  return (d1.a*d2.b==d1.b*d2.a);
}

//ray AB, point C
template<class T> long double RayToPoint(Point<T> a, Point<T> b, Point<T> c){
  return (dot(a, b, c)>=0?LineToPoint(a, b, c):min(length(a-c), length(b-c)));
}
```

## Polygon
```cpp!
// Polygon: convex hull, in polygon, convex diameter ..
// Functions with param vector<P<T>> works with both integers and floating points
// Functions with param Polygon works with floating points only.

typedef vector< Point > Polygon;

// Convex Hull:
// If minimum point --> #define REMOVE_REDUNDANT
// Known issues:
// - Max. point does not work when some points are the same.
// Tested:
// - (min points) https://open.kattis.com/problems/convexhull
// - (max points) https://cses.fi/problemset/task/2195

// #define REMOVE_REDUNDANT
template<typename T>
T area2(P<T> a, P<T> b, P<T> c) { return a%b + b%c + c%a; }

template<typename T>
void ConvexHull(vector<P<T>> &pts) {
    sort(pts.begin(), pts.end());
    pts.erase(unique(pts.begin(), pts.end()), pts.end());
    vector<P<T>> up, dn;
    for (int i = 0; i < (int) pts.size(); i++) {
#ifdef REMOVE_REDUNDANT
        while (up.size() > 1 && area2(up[up.size()-2], up.back(), pts[i]) >= 0) up.pop_back();
        while (dn.size() > 1 && area2(dn[dn.size()-2], dn.back(), pts[i]) <= 0) dn.pop_back();
#else
        while (up.size() > 1 && area2(up[up.size()-2], up.back(), pts[i]) > 0) up.pop_back();
        while (dn.size() > 1 && area2(dn[dn.size()-2], dn.back(), pts[i]) < 0) dn.pop_back();
#endif
        up.push_back(pts[i]);
        dn.push_back(pts[i]);
    }
    pts = dn;
    for (int i = (int) up.size() - 2; i >= 1; i--) pts.push_back(up[i]);
    
#ifdef REMOVE_REDUNDANT
    if (pts.size() <= 2) return;
    dn.clear();
    dn.push_back(pts[0]);
    dn.push_back(pts[1]);
    for (int i = 2; i < (int) pts.size(); i++) {
        if (onSegment(dn[dn.size()-2], pts[i], dn.back())) dn.pop_back();
        dn.push_back(pts[i]);
    }
    if (dn.size() >= 3 && onSegment(dn.back(), dn[1], dn[0])) {
        dn[0] = dn.back();
        dn.pop_back();
    }
    pts = dn;
#endif
}

// Area, perimeter, centroid
template<typename T>
T signed_area2(vector<P<T>> p) {
    T area(0);
    for(int i = 0; i < (int) p.size(); i++) {
        area += p[i] % p[(i + 1) % p.size()];
    }
    return area;
}
double area(const Polygon &p) {
    return std::abs(signed_area2(p) / 2.0);
}
Point centroid(Polygon p) {
    Point c(0,0);
    double scale = 3.0 * signed_area2(p);
    for (int i = 0; i < (int) p.size(); i++){
        int j = (i+1) % p.size();
        c = c + (p[i]+p[j])*(p[i].x*p[j].y - p[j].x*p[i].y);
    }
    return c / scale;
}
double perimeter(Polygon p) {
    double res = 0;
    for(int i = 0; i < (int) p.size(); ++i) {
        int j = (i + 1) % p.size();
        res += (p[i] - p[j]).len();
    }
    return res;
}

// Is convex: checks if polygon is convex.
// Return true for degen points (all vertices are collinear)
template<typename T>
bool is_convex(const vector<P<T>> &P) {
    int sz = (int) P.size();
    int min_ccw = 2, max_ccw = -2;
    for (int i = 0; i < sz; i++) {
        int c = ccw(P[i], P[(i+1) % sz], P[(i+2) % sz]);
        min_ccw = min(min_ccw, c);
        max_ccw = max(max_ccw, c);
    }
    return min_ccw * max_ccw >= 0;
}

// Inside polygon: O(N). Works with any polygon
// Tested:
// - https://open.kattis.com/problems/pointinpolygon
// - https://open.kattis.com/problems/cuttingpolygon
enum PolygonLocation { OUT, ON, IN };
PolygonLocation in_polygon(const Polygon &p, Point q) {
    if ((int)p.size() == 0) return PolygonLocation::OUT;

    // Check if point is on edge.
    int n = p.size();
    REP(i,n) {
        int j = (i + 1) % n;
        Point u = p[i], v = p[j];

        if (u > v) swap(u, v);

        if (ccw(u, v, q) == 0 && u <= q && q <= v) return PolygonLocation::ON;
    }

    // Check if point is strictly inside.
    int c = 0;
    for (int i = 0; i < n; i++) {
        int j = (i + 1) % n;
        if (((p[i].y <= q.y && q.y < p[j].y)
                    || (p[j].y <= q.y && q.y < p[i].y))
                && q.x < p[i].x + (p[j].x - p[i].x) * (q.y - p[i].y) / (double) (p[j].y - p[i].y)) {
            c = !c;
        }
    }
    return c ? PolygonLocation::IN : PolygonLocation::OUT;
}

// Check point in convex polygon, O(logN)
#define Det(a,b,c) ((double)(b.x-a.x)*(double)(c.y-a.y)-(double)(b.y-a.y)*(c.x-a.x))
PolygonLocation in_convex(vector<Point>& l, Point p){
    if (l.empty()) return PolygonLocation::OUT;
    if (l.size() <= 2) {
        return onSegment(l[0], l[1 % l.size()], p) ? PolygonLocation::ON : PolygonLocation::OUT;
    }

    int a = 1, b = l.size()-1, c;
    if (Det(l[0], l[a], l[b]) > 0) swap(a,b);

    if (onSegment(l[0], l[a], p)) return ON;
    if (onSegment(l[0], l[b], p)) return ON;

    if (Det(l[0], l[a], p) > 0 || Det(l[0], l[b], p) < 0) return OUT;
    while(abs(a-b) > 1) {
        c = (a+b)/2;
        if (Det(l[0], l[c], p) > 0) b = c; else a = c;
    }
    int t = cmp(Det(l[a], l[b], p), 0);
    return (t == 0) ? ON : (t < 0) ? IN : OUT;
}


// Cut a polygon with a line. Returns half on left-hand-side.
// To return the other half, reverse the direction of Line l (by negating l.a, l.b)
// The line must be formed using 2 points
Polygon polygon_cut(const Polygon& P, Line l) {
    Polygon Q;
    for(int i = 0; i < (int) P.size(); ++i) {
        Point A = P[i], B = (i == ((int) P.size())-1) ? P[0] : P[i+1];
        if (ccw(l.A, l.B, A) != -1) Q.push_back(A);
        if (ccw(l.A, l.B, A)*ccw(l.A, l.B, B) < 0) {
            Point p; areIntersect(Line(A, B), l, p);
            Q.push_back(p);
        }
    }
    return Q;
}

// Find intersection of 2 convex polygons
// Helper method
bool intersect_1pt(Point a, Point b,
    Point c, Point d, Point &r) {
    double D =  (b - a) % (d - c);
    if (cmp(D, 0) == 0) return false;
    double t =  ((c - a) % (d - c)) / D;
    double s = -((a - c) % (b - a)) / D;
    r = a + (b - a) * t;
    return cmp(t, 0) >= 0 && cmp(t, 1) <= 0 && cmp(s, 0) >= 0 && cmp(s, 1) <= 0;
}
Polygon convex_intersect(Polygon P, Polygon Q) {
    const int n = P.size(), m = Q.size();
    int a = 0, b = 0, aa = 0, ba = 0;
    enum { Pin, Qin, Unknown } in = Unknown;
    Polygon R;
    do {
        int a1 = (a+n-1) % n, b1 = (b+m-1) % m;
        double C = (P[a] - P[a1]) % (Q[b] - Q[b1]);
        double A = (P[a1] - Q[b]) % (P[a] - Q[b]);
        double B = (Q[b1] - P[a]) % (Q[b] - P[a]);
        Point r;
        if (intersect_1pt(P[a1], P[a], Q[b1], Q[b], r)) {
            if (in == Unknown) aa = ba = 0;
            R.push_back( r );
            in = B > 0 ? Pin : A > 0 ? Qin : in;
        }
        if (C == 0 && B == 0 && A == 0) {
            if (in == Pin) { b = (b + 1) % m; ++ba; }
            else            { a = (a + 1) % m; ++aa; }
        } else if (C >= 0) {
            if (A > 0) { if (in == Pin) R.push_back(P[a]); a = (a+1)%n; ++aa; }
            else       { if (in == Qin) R.push_back(Q[b]); b = (b+1)%m; ++ba; }
        } else {
            if (B > 0) { if (in == Qin) R.push_back(Q[b]); b = (b+1)%m; ++ba; }
            else       { if (in == Pin) R.push_back(P[a]); a = (a+1)%n; ++aa; }
        }
    } while ( (aa < n || ba < m) && aa < 2*n && ba < 2*m );
    if (in == Unknown) {
        if (in_convex(Q, P[0])) return P;
        if (in_convex(P, Q[0])) return Q;
    }
    return R;
}

// Find the diameter of polygon.
// Returns:
// <diameter, <ids of 2 points>>
pair<double, pair<int,int>> convex_diameter(const Polygon &p) {
    const int n = p.size();
    int is = 0, js = 0;
    for (int i = 1; i < n; ++i) {
        if (p[i].y > p[is].y) is = i;
        if (p[i].y < p[js].y) js = i;
    }
    double maxd = (p[is]-p[js]).len();
    int i, maxi, j, maxj;
    i = maxi = is;
    j = maxj = js;
    do {
        int ii = (i+1) % n, jj = (j+1) % n;
        if ((p[ii] - p[i]) % (p[jj] - p[j]) >= 0) j = jj;
        else i = ii;
        if ((p[i] - p[j]).len() > maxd) {
            maxd = (p[i] - p[j]).len();
            maxi = i;
            maxj = j;
        }
    } while (i != is || j != js);
    return {maxd, std::minmax(maxi, maxj)}; /* farthest pair is (maxi, maxj). */
}

// Pick theorem
// Given non-intersecting polygon.
// S = area
// I = number of integer points strictly Inside
// B = number of points on sides of polygon
// S = I + B/2 - 1
```