咕咕嘎嘎之傻九嘿嘿嘿

Fool

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    return 0;
}

图论

强连通分量缩点
struct SCC {
    int n, dfncnt, cnt;
    vector<int> stk;
    vector<int> dfn, low, flag;
    vector<vector<int>> e;

    SCC() {}
    SCC(int n) {
        init(n);
    }

    void init(int n) {
        this->n = n;
        stk.clear();
        dfn.assign(n, -1);
        low.assign(n, -1);
        flag.assign(n, -1);
        e.assign(n, {});
        dfncnt = cnt = 0;
    }

    void addedge(int u, int v) {
        e[u].push_back(v);
    }

    void dfs(int u) {
        stk.push_back(u);
        dfn[u] = low[u] = dfncnt++;

        for (auto v : e[u]) {
            if (dfn[v] == -1) {
                dfs(v);
                low[u] = min(low[u], low[v]);
            } else if (flag[v] == -1) {
                low[u] = min(low[u], dfn[v]);
            }
        }

        if (dfn[u] == low[u]) {
            while (stk.back() != u) {
                flag[stk.back()] = cnt;
                stk.pop_back();
            }
            stk.pop_back();
            flag[u] = cnt++;
        }
    }

    vector<int> work() {
        for (int i = 0; i < n; i++) {
            if (dfn[i] == -1) {
                dfs(i);
            }
        }
        return flag;
    }
};
点双
int dfncnt = 0;  
vector<int> dfn(n + 1, 0), low(n + 1, 0);  
stack<int> st;  
vector<vector<int>> ans;  
auto tarjan = [&](auto self, int u, int fa) -> void {  
    st.push(u);  
    dfn[u] = low[u] = ++dfncnt;  
    int son = 0;  
    for (auto v : e[u]) {  
        if (dfn[v] == 0) {  
            ++son;  
            self(self, v, u);  
            low[u] = min(low[v], low[u]);  
            if (low[v] >= dfn[u]) {  
                vector<int> cur;  
                while (st.top() != v) {
                    cur.emplace_back(st.top());    //将同一个点双的点放进同一个vector  
                    st.pop();  
                }  
                cur.emplace_back(v);
                st.pop();  
                cur.emplace_back(u);  
                ans.emplace_back(cur);  
            }  
        } else if (v != fa) {  
            low[u] = min(low[u], dfn[v]);          //对于点双,右边只能是dfn  
        }  
    }  
    if (fa == -1 && son == 0) {  
        vector<int> cur(1, u);  
        ans.emplace_back(cur);  
    }  
};  
for (int i = 1; i <= n; i++) {  
    if (dfn[i] == 0) {  
        while (!st.empty()) st.pop();  
        tarjan(tarjan, i, -1);  
    }  
}
边双
int dfncnt = 0;  
vector<int> dfn(n + 1, 0), low(n + 1, 0);  
stack<int> st;  
auto tarjan = [&](auto self, int u, int fa) -> void {  
    st.push(u);  
    dfn[u] = low[u] = ++dfncnt;  
    for (auto v : e[u]) {  
        if (dfn[v] == 0) {  
            self(self, v, u);  
            low[u] = min(low[u], low[v]);  
        } else if (v != fa) {  
            low[u] = min(low[u], dfn[v]);  
        }  
    }  
    if (dfn[u] == low[u]) {  
        while (st.top() != u) {  
            merge(st.top(), u);            //将同一个边双的点合并  
            st.pop();  
        }  
        st.pop();  
    }  
};  
for (int i = 0; i <= n; i++) {  
    if (dfn[i] == 0) {  
        tarjan(tarjan, i, -1);  
    }  
}
twosat
struct TwoSat {  
    int n;  
    vector<vector<int>> e;  
    vector<bool> ans;  
  
    TwoSat(int n) : n(n), e(2 * n), ans(n) {}  
  
    // u为true,或者v为true  
    // u(false)->v(true)  
    // v(false)->u(true)  
    void addedge(int u, bool a, int v, bool b) {  
        e[2 * u + !a].push_back(2 * v + b);  
        e[2 * v + !b].push_back(2 * u + a);  
    }  
  
    bool satisfible() {  
        int dfncnt = 0, cnt = 0;  
        vector<int> dfn(2 * n), low(2 * n), id(2 * n);  
        stack<int> stk;  
        auto tarjan = [&](auto self, int u) -> void {  
            stk.push(u);  
            dfn[u] = low[u] = ++dfncnt;  
            for (auto v : e[u]) {  
                if (dfn[v] == 0) {  
                    self(self, v);  
                    low[u] = min(low[u], low[v]);  
                } else if (id[v] == 0) {  
                    low[u] = min(low[u], dfn[v]);  
                }  
            }  
            if (dfn[u] == low[u]) {  
                ++cnt;  
                int v;  
                do {  
                    v = stk.top();  
                    stk.pop();  
                    id[v] = cnt;  
                } while (v != u);  
            }  
        };  
        for (int i = 0; i < 2 * n; i++) {  
            if (dfn[i] == 0) {  
                tarjan(tarjan, i);  
            }  
        }  
        for (int i = 0; i < n; i++) {  
            if (id[2 * i] == id[2 * i | 1]) {  
                return false;  
            }  
            ans[i] = id[2 * i] > id[2 * i | 1];  
        }  
        return true;  
    }  
  
    vector<bool> answer() {  
        return ans;  
    }  
};
最大流
using i64 = long long;  
struct maxflow {  
    struct Edge {  
        int to;  
        i64 cap;  
        Edge(int to, i64 cap) : to(to), cap(cap) {}  
    };  
  
    int n;  
    vector<Edge> edges;  
    vector<vector<int>> e;  
    vector<int> cur, dep;  
  
    maxflow() {}  
    maxflow(int n) {  
        init(n);  
    }  
  
    void init(int n) {  
        this->n = n;  
        edges.clear();  
        e.assign(n, {});  
        cur.resize(n);  
        dep.resize(n);  
    }  
  
    bool bfs(int s, int t) {  
        dep.assign(n, 0); dep[s] = 1;  
        queue<int> q; q.push(s);  
        while (!q.empty()) {  
            const int u = q.front(); q.pop();  
            for (int i : e[u]) {  
                auto [v, c] = edges[i];  
                if (dep[v] == 0 && c > 0) {  
                    dep[v] = dep[u] + 1;  
                    if (v == t) {  
                        return true;  
                    }  
                    q.push(v);  
                }  
            }  
        }  
        return false;  
    }  
  
    i64 dfs(int u, int t, i64 f) {  
        if (u == t || f == 0) {  
            return f;  
        }  
        i64 ret = 0;  
        for (int &i = cur[u]; i < int(e[u].size()); ++i) {  
            const int j = e[u][i];  
            auto [v, c] = edges[j];  
            if (c > 0 && dep[v] == dep[u] + 1) {  
                i64 k = dfs(v, t, min(f - ret, c));  
                edges[j].cap -= k;  
                edges[j  ^ 1].cap += k;  
                ret += k;  
                if (ret == f) {  
                    return f;  
                }  
            }  
        }  
        return ret;  
    }  
  
    void addedge(int u, int v, i64 c) {  
        e[u].push_back(edges.size());  
        edges.emplace_back(v, c);  
        e[v].push_back(edges.size());  
        edges.emplace_back(u, 0);  
    }  
  
    i64 flow(int s, int t) {  
        i64 ret = 0;  
        while (bfs(s, t)) {  
            cur.assign(n, 0);  
            ret += dfs(s, t, LONG_LONG_MAX);  
        }  
        return ret;  
    }  
};
费用流
struct mcflow {
    struct Edge {
        int v, f, c;
        Edge(int v, int f, int c) : v(v), f(f), c(c) {}
    };

    const int n;
    vector<Edge> edges;
    vector<vector<int>> e;
    vector<i64> h, dis;
    vector<int> pre;

    mcflow(int n) : n(n), e(n) {}

    void addedge(int u, int v, int f, int c) {
        e[u].push_back(edges.size());
        edges.emplace_back(v, f, c);
        e[v].push_back(edges.size());
        edges.emplace_back(u, 0, -c);
    }

    bool Dijstra(int s, int t) {
        dis.assign(n, LONG_LONG_MAX);
        pre.assign(n, -1);
        priority_queue<pair<i64, int>, vector<pair<i64, int>>, greater<pair<i64, int>>> pq;
        dis[s] = 0;
        pq.emplace(0, s);
        while (!pq.empty()) {
            auto [d, u] = pq.top();
            pq.pop();
            if (dis[u] < d) {
                continue;
            }
            for (int i : e[u]) {
                auto [v, f, c] = edges[i];
                if (f > 0 && dis[v] > d + h[u] - h[v] + c) {
                    dis[v] = d + h[u] - h[v] + c;
                    pre[v] = i;
                    pq.emplace(dis[v], v);
                }
            }
        }
        return dis[t] != LONG_LONG_MAX;
    }

    pair<int, i64> flow(int s, int t) {
        int flow = 0;
        i64 cost = 0;
        h.assign(n, 0);
        while (Dijstra(s, t)) {
            for (int i = 0; i < n; i++) {
                h[i] += dis[i];
            }
            int aug = INT_MAX;
            for (int i = t; i != s; i = edges[pre[i] ^ 1].v) {
                aug = min(aug, edges[pre[i]].f);
            }
            for (int i = t; i != s; i = edges[pre[i] ^ 1].v) {
                edges[pre[i]].f -= aug;
                edges[pre[i] ^ 1].f += aug;
            }
            flow += aug;
            cost += i64(aug) * h[t];
        }

        return make_pair(flow, cost);
    }
};
树剖
vector<int> dep(n, 0), siz(n, 0), fa(n, 0), hson(n, -1);
auto dfs1 = [&](auto self, int u) -> void {
    siz[u] = 1;
    for (auto v : e[u]) {
        if (v == fa[u]) {
            continue;
        }
        fa[v] = u;
        dep[v] = dep[u] + 1;
        self(self, v);
        siz[u] += siz[v];
        if (hson[u] == -1 || siz[v] > siz[hson[u]]) {
            hson[u] = v;
        }
    }
};

int dfncnt = 0;
vector<int> dfn(n, -1), top(n, 0), rank(n + 1, 0), bot(n, -1);
auto dfs2 = [&](auto self, int u, int t) -> void {
    top[u] = t;
    dfn[u] = ++dfncnt;
    rank[dfncnt] = u;
    if (hson[u] != -1) {
        self(self, hson[u], t);
    }
    for (auto v : e[u]) {
        if (v == fa[u] || v == hson[u]) {
            continue;
        }
        self(self, v, v);
    }
    bot[u] = dfncnt;
};
虚树

看个大概

auto g = e;
vector<int> flag(n, 0);

for (int q = 1; q <= Q; q++) {
    int m;
    cin >> m;

    vector<int> a(m);
    for (int i = 0; i < m; i++) {
        cin >> a[i];
        a[i]--;
        flag[a[i]] = q;
    }

    sort(a.begin(), a.end(), [&](int u, int v) -> bool { return dfn[u] < dfn[v]; });

    stack<int> stk;
    stk.push(0);
    g[0].clear();

    for (auto u : a) {
        int p = lca(u, stk.top());
        if (p != stk.top()) {
            int v = stk.top();
            stk.pop();

            while (dfn[stk.top()] > dfn[p]) {
                g[stk.top()].emplace_back(v);
                v = stk.top();
                stk.pop();
            }

            if (dfn[stk.top()] != dfn[p]) {
                g[p].clear();
                stk.push(p);
            }
            g[stk.top()].emplace_back(v);
        }
        stk.push(u);
        g[u].clear();
    }

    int cur = stk.top();
    stk.pop();
    while (!stk.empty()) {
        g[stk.top()].emplace_back(cur);
        cur = stk.top();
        stk.pop();
    }
}
树分治
#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using u64 = unsigned long long;

struct Edge {
    int u, v, w;
};

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<Edge> edg(n - 1);
    vector<vector<int>> e(n);

    for (int i = 0; i < n - 1; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--;
        v--;
        edg[i].u = u;
        edg[i].v = v;
        edg[i].w = w;
        e[u].push_back(i);
        e[v].push_back(i);
    }

    vector<int> siz(n), vis(n), dis(n);

    auto init = [&]() -> void {
        
    };

    auto dfs1 = [&](auto self, int u, int p) -> void {
        siz[u] = 1;
        for (auto i : e[u]) {
            int v = u ^ edg[i].u ^ edg[i].v;
            if (v == p || vis[v]) {
                continue;
            }

            self(self, v, u);
            siz[u] += siz[v];
        }
    };

    auto find = [&](auto self, int u, int p, int rt) -> int {
        for (auto i : e[u]) {
            int v = u ^ edg[i].u ^ edg[i].v;
            if (v == p || vis[v]) {
                continue;
            }

            if (2 * siz[v] >= siz[rt]) {
                return self(self, v, u, rt);
            }
        }
        return u;
    };

    auto dfs2 = [&](auto self, int u, int p) -> void {
        // ???
        for (auto i : e[u]) {
            int v = u ^ edg[i].u ^ edg[i].v;
            if (v == p || vis[v]) {
                continue;
            }

            dis[v] = dis[u] + edg[i].w;
            self(self, v, u);
        }
    };

    queue<int> q;
    q.push(0);

    int ans = 0;

    while (!q.empty()) {
        auto u = q.front();
        q.pop();

        dfs1(dfs1, u, u);
        u = find(find, u, u, u);

        init();
        dis[u] = 0;

        // ???

        vis[u] = 1;
        for (auto i : e[u]) {
            int v = u ^ edg[i].u ^ edg[i].v;
            if (vis[v]) {
                continue;
            }

            q.push(v);
        }
    }

    return 0;
}
树hash
const int N = 1e6;
const u64 seed = mt19937_64(time(nullptr))();

vector<u64> Hash(N);
vector<vector<int>> e(N);

u64 shift(u64 x) {
    x ^= x << 13;
    x ^= x >> 7;
    x ^= x << 17;
    return x;
}

void dfs(int u, int p) {
    Hash[u] = 1;
    for (auto v : e[u]) {
        if (v == p) {
            continue;
        }
        dfs(v, u);
        Hash[u] += shift(Hash[v]);
    }
}

数论

线性筛
vector<int> minp, primes;
  
void sieve(int n) {  
    minp.assign(n + 1, 0);  
    primes.clear();  
      
    for (int i = 2; i <= n; i++) {  
        if (minp[i] == 0) {  
            minp[i] = i;  
            primes.push_back(i);  
        }  
          
        for (auto p : primes) {  
            if (i * p > n) {  
                break;  
            }  
            minp[i * p] = p;  
            if (p == minp[i]) {  
                break;  
            }  
        }  
    }  
}

/*
*********************************************
*/

vector<int> minp, primes, phi;

void sieve(int n) {
    primes.clear();
    phi.assign(n + 1, 0);
    minp.assign(n + 1, 0);
    phi[1] = 1;

    for (int i = 2; i <= n; i++) {
        if (minp[i] == 0) {
            minp[i] = i;
        	phi[i] = i - 1;
            primes.push_back(i);
        }
        
        for (auto p : primes) {
            if (i * p > n) {
                break;
            }
            minp[i * p] = p;
            if (p == minp[i]) {
            	phi[i * p] = phi[i] * p;
                break;
            }
            phi[i * p] = phi[i] * (p - 1);
        }
    }
}

/*
*********************************************
*/

vector<int> minp, primes, mu;

void sieve(int n) {
    minp.assign(n + 1, 0);
    mu.assign(n + 1, 0);
    primes.clear();
    mu[1] = 1;

    for (int i = 2; i <= n; i++) {
        if (minp[i] == 0) {
            minp[i] = i;
            mu[i] = -1;
            primes.push_back(i);
        }
        
        for (auto p : primes) {
            if (i * p > n) {
                break;
            }
            minp[i * p] = p;
            if (p == minp[i]) {
                break;
            }
            mu[i * p] = -mu[i];
        }
    }
}

/*
*********************************************
*/

// 和函数, o(nloglogn)

for (int i = 1; i <= n; i++) {
	F[i] = f[i];
}

for (auto p : primes) {
	for (int i = 1; i * p <= n; i++) {
		F[i * p] += f[i];
	}
}
杜教筛
#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using u64 = unsigned long long;

const int N = 1000000;

vector<int> minp, primes, phi, mu;

void sieve(int n) {
    minp.assign(n + 1, 0);
    phi.assign(n + 1, 0);
    mu.assign(n + 1, 0);
    primes.clear();
    phi[1] = mu[1] = 1;

    for (int i = 2; i <= n; i++) {
        if (minp[i] == 0) {
            minp[i] = i;
            phi[i] = i - 1;
            mu[i] = -1;
            primes.push_back(i);
        }
        
        for (auto p : primes) {
            if (i * p > n) {
                break;
            }
            minp[i * p] = p;
            if (p == minp[i]) {
                phi[i * p] = phi[i] * p;
                break;
            }
            phi[i * p] = phi[i] * (p - 1);
            mu[i * p] = -mu[i];
        }
    }
}

vector<i64> pre_mu, pre_phi;
unordered_map<i64, i64> fMu, fPhi;

i64 get_mu(i64 n) {
    if (n <= i64(N)) {
        return pre_mu[n];
    }

    if (fMu.count(n)) {
        return fMu[n];
    }

    i64 ret = 1;
    for (i64 L = 2, R; L <= n; L = R + 1) {
        R = n / (n / L);
        ret -= 1LL * (R - L + 1) * get_mu(n / L);
    }
    fMu[n] = ret;
    return ret;
}

i64 get_phi(i64 n) {
    if (n <= i64(N)) {
        return pre_phi[n];
    }

    if (fPhi.count(n)) {
        return fPhi[n];
    }

    i64 ret = 1LL * n * (n + 1) / 2;
    for (i64 L = 2, R; L <= n; L = R + 1) {
        R = n / (n / L);
        ret -= 1LL * (R - L + 1) * get_phi(n / L);
    }
    fPhi[n] = ret;
    return ret;
}

void solve() {
    i64 n;
    cin >> n;

    cout << get_phi(n) << " " << get_mu(n) << "\n";
}

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    sieve(N);
    pre_mu.assign(N + 1, 0);
    pre_phi.assign(N + 1, 0);
    for (int i = 1; i <= N; i++) {
        pre_mu[i] = pre_mu[i - 1] + mu[i];
        pre_phi[i] = pre_phi[i - 1] + phi[i];
    }

    solve();

    return 0;
}
求单个欧拉函数
int phi(int x) {
	int ret = x;
	for (int i = 2; i * i <= x; i++) {
		if (x % i == 0) {
			while (x % i == 0) {
				x /= i;
			}
			ret = ret / i * (i - 1);
		}
	}
	if (x > 1) {
		ret = ret / x * (x - 1);
	}
	return ret;
}
素性测试与因式分解
i64 Mul(i64 x, i64 y, i64 mod) {
    return static_cast<__int128>(x) * y % mod;
}

i64 power(i64 x, i64 n, i64 mod) {
    i64 ret = 1;
    while (n > 0LL) {
        if (n & 1) {
            ret = Mul(ret, x, mod);
        }
        n >>= 1;
        x = Mul(x, x, mod);
    }
    return ret;
}

// 素数返回true
bool isprime(i64 x) {
    vector<i64> test = { 2,3,5,7,11,13,17,19,23,29,31,37 };

    if (x <= 40LL) {
        for (auto y : test) {
            if (x == y) {
                return true;
            }
        }
        return false;
    }

    int v = __builtin_ctzll(x - 1);
    i64 u = (x - 1) >> v;

    for (auto y : test) {
        i64 z = power(y, u, x);
        for (int i = 0; i < v; i++) {
            i64 nz = Mul(z, z, x);
            if (nz == 1 && z != 1 && z != x - 1) {
                return false;
            }
            z = nz;
        }
        if (z != 1) {
            return false;
        }
    }

    return true;
}

vector<i64> factorize(i64 n) {
    vector<i64> ret;

    auto f = [&](auto self, i64 z) -> void {
        if (isprime(z)) {
            ret.push_back(z);
            return;
        }

        i64 p = z;
        while (p >= z) {
            i64 i = 1, k = 2;
            i64 c = rand() % (p - 1) + 1;
            i64 x = rand() % p;
            i64 y = x;
            while (true) {
                i++;
                x = (Mul(x, x, p) + c) % p;
                i64 d = gcd(abs(x - y), p);
                if (d != 1 && d != p) {
                    p = d;
                    break;
                }
                if (y == x) {
                    break;
                }
                if (i == k) {
                    y = x;
                    k <<= 1;
                }
            }
        }

        self(self, p);
        self(self, z / p);
    };
    f(f, n);

    sort(ret.begin(), ret.end());
    return ret;
}
不可靠的fft
constexpr double Pi = 3.1415926535897;

vector<int> rev;

struct Complex {
    double x, y;

    Complex() {}
    Complex(double x, double y) : x(x), y(y) {}

    Complex operator + (Complex B) {
        return Complex(x + B.x, y + B.y);
    }
    Complex operator - (Complex B) {
        return Complex(x - B.x, y - B.y);
    }
    Complex operator * (Complex B) {
        return Complex(x * B.x - y * B.y, x * B.y + y * B.x);
    }
};

void FFT(vector<Complex> &A) {
    int n = int(A.size());
    for (int i = 0; i < n; i++) {
        if (i < rev[i]) {
            swap(A[i], A[rev[i]]);
        }
    }
    for (int i = 1; i < n; i <<= 1) {
        auto W = Complex(cos(Pi / i), sin(Pi / i));
        for (int j = 0; j < n; j += (i << 1)) {
            auto w = Complex(1.0, 0.0);
            for (int k = 0; k < i; k++, w = w * W) {
                auto x = A[j + k], y = w * A[j + k + i];
                A[j + k] = x + y;
                A[j + k + i] = x - y;
            }
        }
    }
}

void IFFT(vector<Complex> &A) {
    FFT(A);
    reverse(A.begin() + 1, A.end());
}

vector<i64> Mul(vector<i64> a, vector<i64> b) {
    int N = int(a.size()), M = int(b.size());
    int n = 1, bit = 0, tot = N + M - 1;
    while (n < tot) {
        bit++;
        n <<= 1;
    }
    if (tot < 1024) {
        vector<i64> c(tot);
        for (int i = 0; i < int(a.size()); i++) {
            for (int j = 0; j < int(b.size()); j++) {
                c[i + j] = c[i + j] + 1LL * a[i] * b[j];
            }
        }
        return c;
    }

    vector<Complex> A(n), B(n);
    for (int i = 0; i < N; i++) {
        A[i] = Complex(a[i], 0);
    }
    for (int i = 0; i < M; i++) {
        B[i] = Complex(b[i], 0);
    }
    rev.resize(n);
    for (int i = 0; i < n; i++) {
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
    }

    FFT(A), FFT(B);
    for (int i = 0; i < n; i++) {
        A[i] = A[i] * B[i];
    }
    IFFT(A);

    a.resize(tot);
    for (int i = 0; i < tot; i++) {
        a[i] = i64(A[i].x / n + 0.5);
    }
    return a;
}
NTT
constexpr int P = 998244353;

int power(int a, int b) {
    int res = 1;
    for (; b; b /= 2, a = 1LL * a * a % P) {
        if (b % 2) {
            res = 1LL * res * a % P;
        }
    }
    return res;
}

vector<int> rev, roots;

void dft(vector<int> &a) {
    int n = a.size();
    if (int(rev.size()) != n) {
        int k = __builtin_ctz(n) - 1;
        rev.resize(n);
        for (int i = 0; i < n; i++) {
            rev[i] = rev[i >> 1] >> 1 | (i & 1) << k;
        }
    }
    for (int i = 0; i < n; i++) {
        if (rev[i] < i) {
            swap(a[i], a[rev[i]]);
        }
    }
    if (roots.size() < n) {
        int k = __builtin_ctz(roots.size());
        roots.resize(n);
        while ((1 << k) < n) {
            int e = power(31, 1 << (__builtin_ctz(P - 1) - k - 1));
            for (int i = 1 << (k - 1); i < (1 << k); i++) {
                roots[2 * i] = roots[i];
                roots[2 * i + 1] = 1LL * roots[i] * e % P;
            }
            k++;
        }
    }

    for (int k = 1; k < n; k *= 2) {
        for (int i = 0; i < n; i += 2 * k) {
            for (int j = 0; j < k; j++) {
                int u = a[i + j];
                int v = 1LL * a[i + j + k] * roots[k + j] % P;
                a[i + j] = (u + v) % P;
                a[i + j + k] = ((u - v) % P + P) % P;
            }
        }
    }
}

void idft(vector<int> &a) {
    int n = a.size();
    reverse(a.begin() + 1, a.end());
    dft(a);
    int inv = power(n, P - 2);
    for (int i = 0; i < n; i++) {
        a[i] = 1LL * a[i] * inv % P;
    }
}

vector<int> mul(vector<int> a, vector<int> b) {
    rev.clear();
    roots = {0, 1};
    int n = 1, tot = a.size() + b.size() - 1;
    while (n < tot) {
        n *= 2;
    }
    if (tot < 128) {
        vector<int> c(a.size() + b.size() - 1);
        for (int i = 0; i < a.size(); i++) {
            for (int j = 0; j < b.size(); j++) {
                c[i + j] = (c[i + j] + 1LL * a[i] * b[j]) % P;
            }
        }
        return c;
    }
    a.resize(n);
    b.resize(n);
    dft(a);
    dft(b);
    for (int i = 0; i < n; i++) {
        a[i] = 1LL * a[i] * b[i] % P;
    }
    idft(a);
    a.resize(tot);
    return a;
}

几何

凹包, 旋转卡壳
struct Point {
    i64 x, y;

    Point() {}
    Point(i64 x, i64 y) : x(x), y(y) {}

    Point operator + (Point B) {
        return Point(x + B.x, y + B.y);
    }
    Point operator - (Point B) {
        return Point(x - B.x, y - B.y);
    }
    bool operator == (Point B) const {
        return x == B.x && y == B.y;
    }
    bool operator < (Point B) const {
        return x < B.x || (x == B.x && y < B.y);
    }
};
typedef Point Vector;

// 点乘
i64 dot(const Vector &A, const Vector &B) {
    return A.x * B.x + A.y * B.y;
}

// 叉乘
i64 cross(const Vector &A, const Vector &B) {
    return A.x * B.y - A.y * B.x;
}

// 距离
double distance(const Point &A, const Point &B) {
    return hypot(A.x - B.x, A.y - B.y);
}

// 距离的平方
i64 dis_double(const Point &A, const Point &B) {
    return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y);
}

// 面积
i64 getarea(Vector A, Vector B) {
    return llabs(cross(A, B));
}

vector<Point> getHull(vector<Point> p) {
    sort(p.begin(), p.end());
    p.erase(unique(p.begin(), p.end()), p.end());
    if (p.size() <= 1) {
        return p;
    }

    vector<Point> h, l;
    for (auto a : p) {
        while (h.size() > 1 && cross(a - h.back(), a - h[h.size() - 2]) <= 0) {
            h.pop_back();
        }
        while (l.size() > 1 && cross(a - l.back(), a - l[l.size() - 2]) >= 0) {
            l.pop_back();
        }
        h.push_back(a);
        l.push_back(a);
    }
    l.pop_back();
    reverse(h.begin(), h.end());
    h.pop_back();
    l.insert(l.end(), h.begin(), h.end());
    return l;
}

// 直径的平方
i64 getlongest(vector<Point> p) {
    p.push_back(p.front());
    if (p.size() < 4) {
        return dis_double(p[0], p[1]);
    }

    i64 ret = 0;
    for (int i = 1, j = 2, n = p.size(); i < p.size(); i++) {
        while (getarea(p[i] - p[i - 1], p[j] - p[i - 1]) <= getarea(p[i] - p[i - 1], p[(j + 1) % n] - p[i - 1])) {
            j = (j + 1) % n;
        }
        ret = max({ret, dis_double(p[j], p[i - 1]), dis_double(p[j], p[i])});
    }
    return ret;
}
疑点重重的半平面交
#include <bits/stdc++.h>
using namespace std;

using i64 = long long;

const double Pi = acos(-1.0);
const double eps = 1e-8;

int sgn(double x) {
    if (fabs(x) <= eps) return 0;
    return x > 0 ? 1 : -1;
}

int dcmp(double x, double y) {
    if (fabs(x - y) <= eps) return 0;
    return x - y > 0 ? 1 : -1;
}

struct Point {
    double x, y;

    Point() {}
    Point(double x, double y) : x(x), y(y) {}

    Point operator + (Point B) {
        return Point(x + B.x, y + B.y);
    }
    Point operator - (Point B) {
        return Point(x - B.x, y - B.y);
    }
    Point operator * (double k) {
        return Point(x * k, y * k);
    }
    Point operator / (double k) {
        return Point(x / k, y / k);
    }
    bool operator == (const Point &B) const {
        return sgn(x - B.x) == 0 && sgn(y - B.y) == 0;
    }
    bool operator < (const Point &B) const {
        return sgn(x - B.x) < 0 || (sgn(x - B.x) == 0 && sgn(y - B.y) < 0);
    }
};
typedef Point Vector;

double Distance(const Point &A, const Point &B) {
    return hypot(A.x - B.x, A.y - B.y);
}

double Dot(const Vector &A, const Vector &B) {
    return A.x * B.x + A.y * B.y;
}

double Len(const Vector &A) {
    return sqrt(Dot(A, A));
}

double Cross(const Vector &A, const Vector &B) {
    return A.x * B.y - A.y * B.x;
}

double Area2(Point A, Point B, Point C) {
    return Cross(B - A, C - A);
}

// 逆时针旋转rad
Vector Rotate(const Vector &A, double rad) {
    return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
}

// 逆时针旋转90度
Vector Rotate2(const Vector &A) {
    return Vector(-A.y, A.x);
}

// 检查两个向量是否平行
bool Parallel(const Vector &A, const Vector &B) {
    return sgn(Cross(A, B)) == 0;
}

struct Line {
    Point p;
    Vector v;
    double ang;

    Line() {}
    Line(Point p, Vector v) : p(p), v(v) { ang = atan2(v.y, v.x); }

    bool operator < (const Line &B) const {
        return ang < B.ang;
    }
};

bool Onleft(const Line &L, Point p) {
    return sgn(Cross(L.v, p - L.p)) > 0;
}

Point Cross_point(Line A, Line B) {
    Vector u = A.p - B.p;
    double t = Cross(B.v, u) / Cross(A.v, B.v);
    return A.p + A.v * t;
}

vector<Point> HPI(vector<Line> L) {
    const int n = L.size();
    sort(L.begin(), L.end());

    deque<Line> l;
    deque<Point> p;
    l.emplace_back(L[0]);
    for (int i = 1; i < n; i++) {
        while (p.size() > 0 && !Onleft(L[i], p.back())) {
            p.pop_back();
            l.pop_back();
        }
        while (p.size() > 0 && !Onleft(L[i], p.front())) {
            p.pop_front();
            l.pop_front();
        }

        if (sgn(Cross(L[i].v, l.back().v)) == 0) {
            if (Onleft(l.back(), L[i].p)) {
                l.pop_back();
                if (l.size() > 0) {
                    p.pop_back();
                    p.emplace_back(Cross_point(L[i], l.back()));
                }
                l.emplace_back(L[i]);
            }
        } else {
            p.emplace_back(Cross_point(L[i], l.back()));
            l.emplace_back(L[i]);
        }
    }

    while (p.size() > 0 && !Onleft(l.front(), p.back())) {
        l.pop_back();
        p.pop_back();
    }

    vector<Point> ret;
    if (l.size() <= 2) {
        return ret;
    }
    p.emplace_back(Cross_point(l.front(), l.back()));
    for (auto x : p) {
        ret.emplace_back(x);
    }
    return ret;
}

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<Line> L;
    while (n--) {
        int m;
        cin >> m;

        vector<int> x(m + 1), y(m + 1);
        for (int i = 0; i < m; i++) {
            cin >> x[i] >> y[i];
        }
        x[m] = x[0], y[m] = y[0];

        for (int i = 0; i < m; i++) {
            L.emplace_back(Line(Point(x[i], y[i]), Vector(x[i + 1] - x[i], y[i + 1] - y[i])));
        }
    }

    auto Hull = HPI(L);
    double ans = 0;
    for (int i = 2; i < Hull.size(); i++) {
        ans += Cross(Hull[i - 1] - Hull.front(), Hull[i] - Hull.front()) / 2;
    }
    printf("%.3f\n", ans);

    return 0;
}
完全正确的平面最近点对
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
const double inf = 1e20;

struct Point {
    double x, y;
    Point() {}
    Point(double x, double y) : x(x), y(y) {}
};

int sgn(double x) {
    if (fabs(x) < eps) return 0;
    return x < 0 ? -1 : 1;
}

double distance(Point A, Point B) {
    return hypot(A.x - B.x, A.y - B.y);
}

bool cmpxy(Point A, Point B) {
    return sgn(A.x - B.x) < 0 || (sgn(A.x - B.x) == 0 && sgn(A.y - B.y) < 0);
}

bool cmpy(Point A, Point B) {
    return sgn(A.y - B.y) < 0;
}

double closest_pair(vector<Point> &p, int l, int r) {
    double dis = inf;
    if (l == r) return dis;
    if (l + 1 == r) return distance(p[l], p[r]);

    int mid = (l + r) >> 1;
    dis = min(closest_pair(p, l, mid), closest_pair(p, mid + 1, r));
    
    vector<Point> tmp;
    for (int i = l; i <= r; i++) {
        if (fabs(p[mid].x - p[i].x) <= dis) {
            tmp.emplace_back(p[i]);
        }
    }
    sort(tmp.begin(), tmp.end(), cmpy);
    for (int i = 0; i < tmp.size(); i++) {
        for (int j = i + 1; j < tmp.size(); j++) {
            if (tmp[j].y - tmp[i].y >= dis) break;
            dis = min(dis, distance(tmp[i], tmp[j]));
        }
    }
    return dis;
}

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<Point> p(n);
    for (int i = 0; i < n; i++) {
        cin >> p[i].x >> p[i].y;
    }
    sort(p.begin(), p.end(), cmpxy);

    double ans = closest_pair(p, 0, n - 1);
    printf("%.4f\n", ans);

    return 0;
}

数据结构

最爱的dsu
struct DSU {
    vector<int> f, siz;

    DSU() {}
    DSU(int n) {
        init(n);
    }

    void init(int n) {
        f.resize(n);
        iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }

    int find(int x) {
        while (f[x] != x) {
            x = f[x] = f[f[x]];
        }
        return x;
    }

    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }

    int size(int x) {
        return siz[find(x)];
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }
};
可撤销dsu
struct DSU {
    vector<int> f, siz;
    vector<array<int, 2>> his;

    DSU() {}
    DSU(int n) : siz(n, 1), f(n) {
        iota(f.begin(), f.end(), 0);
    }

    int find(int x) {
        while (f[x] != x) {
            x = f[x];
        }
        return x;
    }

    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        if (siz[x] < siz[y]) {
            swap(x, y);
        }
        his.push_back({x, y});
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }

    int time() {
        return his.size();
    }

    void revert(int tim) {
        while (his.size() > tim) {
            auto [x, y] = his.back();
            his.pop_back();
            f[y] = y;
            siz[x] -= siz[y];
        }
    }
};
Fenwick
struct Fenwick {
    int n;
    vector<i64> f;

    Fenwick() {}
    Fenwick(int n) {
        init(n);
    }

    void init(int n) {
        this->n = n;
        f.assign(n + 1, 0);
    }

    void add(int k, i64 x) {
        while (k <= n) {
            f[k] += x;
            k += k & -k;
        }
    }

    i64 sum(int k) {
        i64 ret = 0;
        while (k > 0) {
            ret += f[k];
            k -= k & -k;
        }
        return ret;
    }

    i64 sum(int l, int r) {
        return sum(r) - sum(l - 1);
    }

    void update(int id, i64 x) {
        add(id, x);
        add(id + 1, -x);
    }

    void update(int l, int r, i64 x) {
        add(l, x);
        add(r + 1, -x);
    }

    i64 query(int id) {
        return sum(id);
    }
};
新鲜出炉的哥哥笛卡尔
vector<int> lc(n + 1, 0), rc(n + 1, 0), stk;
for (int i = 1; i <= n; i++) {
	while (!stk.empty() && w[i] < w[stk.back()]) {
		rc[stk.back()] = lc[i];
		lc[i] = stk.back();
		stk.pop_back();
	}
	stk.push_back(i);
}

while (stk.size() > 1) {
	int x = stk.back();
	stk.pop_back();
	rc[stk.back()] = x;
}

字符串

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

vector<int> KMP(string find, string s) {
	string cur = find + "#" + s;
	int siz1 = find.length(), siz2 = s.length();
	vector<int> v;
	vector<int> lps = prefix_function(cur);
	for (int i = siz1 + 1; i <= siz1 + siz2; i++) {
		if (lps[i] == siz1) v.push_back(i - 2 * siz1);
	}
	return v;
}
ZZZZZ
vector<int> z_function(string s) {  
    int n = s.length();  
    vector<int> z(n);  
    for (int i = 1, l = 0, r = 0; i < n; i++) {  
        if (i <= r && z[i - l] < r - i + 1) {  
            z[i] = z[i - l];  
        } else {  
            z[i] = max(0, 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;  
    }  
    return z;  
}
距今10000年前写的aczdj
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
 
int pos = 0;
int trie[maxn][26], num[maxn];
int fail[maxn];
int indegree[maxn], lazy[maxn];
string s[maxn];
int mp[maxn];

void trie_insert(string s, int idx) {
    int p = 0;
    for (auto c : s) {
        int n = c - 'a';
        if (trie[p][n] == 0) {
            trie[p][n] = ++pos;
        }
        p = trie[p][n];
    }
    mp[idx] = p;
}

void get_fail() {
    queue<int> q;
    for (int i = 0; i < 26; i++) {
        if (trie[0][i]) {
            q.push(trie[0][i]);
        }
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = 0; i < 26; i++) {
            if (trie[u][i]) {
                fail[trie[u][i]] = trie[fail[u]][i];
                indegree[fail[trie[u][i]]]++;
                q.push(trie[u][i]);
            } else {
                trie[u][i] = trie[fail[u]][i];
            }
        }
    }
}

void query(string s) {
    int u = 0, res = 0;
    for (int i = 0; i < s.length(); i++) {
        u = trie[u][s[i] - 'a'];
        lazy[u]++;
    }
}

void topsort() {
    queue<int> q;
    for (int i = 1; i <= pos; i++) {
        if (!indegree[i]) q.push(i);
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        num[u] = lazy[u];
        int v = fail[u];
        lazy[v] += lazy[u];
        if (!(--indegree[v])) q.push(v);
    }
}

void solve() {
    int n;
    cin >> n;

    for (int i = 0; i < n; i++) {
        cin >> s[i];
        trie_insert(s[i], i);
    }
    get_fail();

    string T;
    cin >> T;

    query(T);
    topsort();

    for (int i = 0; i < n; i++) {
        cout << num[mp[i]] << endl;
    }

}
posted @ 2025-07-15 10:45  foolnine  阅读(11)  评论(0)    收藏  举报