自用模板整理

动态规划

数位dp

    pos 表示当前枚举到第几位
    sum 表示 d 出现的次数
    limit 为 1 表示枚举的数字有限制
    zero 为 1 表示有前导 0
    d 表示要计算出现次数的数

LL dfs(int pos, LL sum, int limit, int zero, int d) {
    if (pos == 0) return sum;
    if (!limit && !zero && dp[pos][sum] != -1) return dp[pos][sum];
    LL ans = 0;
    int up = (limit ? num[pos] : 9);
    for (int i = 0; i <= up; i++) {
        ans += dfs(pos - 1, sum + ((!zero || i) && (i == d)), limit && (i == num[pos]), zero && (i == 0), d);
    }
    if (!limit && !zero) dp[pos][sum] = ans;
    return ans;
}

LL solve(LL x, int d) {
    memset(dp, -1, sizeof dp);
    int len = 0;
    while (x) {
        num[++len] = x % 10;
        x /= 10;
    }
    return dfs(len, 0, 1, 1, d);
}

数据结构

struct Tree {
    int n;
    vector<vector<pair < int, int>>> e;
    vector<int> dep, parent, maxdep, d1, d2, s1, s2, up;

    Tree(int n) {
        this->n = n;
        e.resize(n + 1);
        dep.resize(n + 1);
        parent.resize(n + 1);
        maxdep.resize(n + 1);
        d1.resize(n + 1);
        d2.resize(n + 1);
        s1.resize(n + 1);
        s2.resize(n + 1);
        up.resize(n + 1);
    }

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

    void dfs(int u, int fa) {
        maxdep[u] = dep[u];
        for (auto [w, v]: e[u]) {
            if (v == fa) continue;
            dep[v] = dep[u] + 1;
            parent[v] = u;
            dfs(v, u);
            maxdep[u] = max(maxdep[u], maxdep[v]);
        }
    }

    void dfs1(int u, int fa) {
        for (auto [w, v]: e[u]) {
            if (v == fa) continue;
            dfs1(v, u);
            int x = d1[v] + w;
            if (x > d1[u]) {
                d2[u] = d1[u], s2[u] = s1[u];
                d1[u] = x, s1[u] = v;
            } else if (x > d2[u]) {
                d2[u] = x, s2[u] = v;
            }
        }
    }

    void dfs2(int u, int fa) {
        for (auto [w, v]: e[u]) {
            if (v == fa) continue;
            if (s1[u] == v) {
                up[v] = max(up[u], d2[u]) + w;
            } else {
                up[v] = max(up[u], d1[u]) + w;
            }
            dfs2(v, u);
        }
    }

    int radius, center, diam;

    void getCenter() {
        center = 1;    //中心
        for (int i = 1; i <= n; i++) {
            if (max(d1[i], up[i]) < max(d1[center], up[center])) {
                center = i;
            }
        }
        radius = max(d1[center], up[center]);    //距离最远点的距离的最小值
        diam = d1[center] + up[center] + 1;    //直径
    }

    int rem;    //删除重心后剩余连通块体积的最小值
    int cog;    //重心
    vector<bool> vis;

    void getCog() {
        vis.resize(n);
        rem = INT_MAX;
        cog = 1;
        dfsCog(1);
    }

    int dfsCog(int u) {
        vis[u] = true;
        int s = 1, res = 0;
        for (auto [w, v]: e[u]) {
            if (vis[v]) continue;
            int t = dfsCog(v);
            res = max(res, t);
            s += t;
        }
        res = max(res, n - s);
        if (res < rem) {
            rem = res;
            cog = u;
        }
        return s;
    }
};

最近公共祖先

struct LCA {
    vector<vector<int>> e;
    vector<int> top, dep, parent, siz, son;

    LCA(int n) {
        e.resize(n + 1);
        top.resize(n + 1);
        dep.resize(n + 1);
        parent.resize(n + 1);
        siz.resize(n + 1);
        son.resize(n + 1);
    }

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

    void dfs1(int u) {
        siz[u] = 1;
        dep[u] = dep[parent[u]] + 1;
        for (auto v: e[u]) {
            if (v == parent[u]) continue;
            parent[v] = u;
            dfs1(v);
            siz[u] += siz[v];
            if (siz[v] > siz[son[u]]) son[u] = v;
        }
    }

    void dfs2(int u, int up) {
        top[u] = up;
        if (son[u]) dfs2(son[u], up);
        for (auto v: e[u]) {
            if (v == parent[u] || v == son[u]) continue;
            dfs2(v, v);
        }
    }

    int lca(int u, int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] > dep[top[v]]) {
                u = parent[top[u]];
            } else {
                v = parent[top[v]];
            }
        }
        return dep[u] < dep[v] ? u : v;
    }
};

线段树

template<class Info>
struct SegmentTree {
    int n;
    vector<Info> info;

    SegmentTree(vector<Info> init) {
        n = init.size();
        info.assign(4 * n, Info());
        function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (l == r) {
                info[p] = init[l - 1];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m + 1, r);
            pull(p);
        };
        build(1, 1, n);
    }

    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }

    void rangeApply(int p, int l, int r, int x, int y) {
        if () {
            return;
        }
        if (l == r) {

            return;
        }
        int m = (l + r) / 2;
        if (x <= m) {
            rangeApply(2 * p, l, m, x, y);
        }
        if (y > m) {
            rangeApply(2 * p + 1, m + 1, r, x, y);
        }
        pull(p);
    }

    void rangeApply(int l, int r) {
        return rangeApply(1, 1, n, l, r);
    }

    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l > y || r < x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m + 1, r, x, y);
    }

    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 1, n, l, r);
    }
};

struct Info {
    LL x = 0, l, r, Max = 0;
};

Info operator+(const Info &a, const Info &b) {
    return Info(a.x + b.x, a.l, b.r, max(a.Max, b.Max));
}

懒标记

template<class Info, class Tag>
struct LazySegmentTree {
    int n;
    vector<Info> info;
    vector<Tag> tag;

    LazySegmentTree(vector<Info> init) {
        n = init.size();
        info.assign(4 * n, Info());
        tag.assign(4 * n, Tag());
        function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (l == r) {
                info[p] = init[l - 1];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m + 1, r);
            pull(p);
        };
        build(1, 1, n);
    }

    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }

    void apply(int p, const Tag &v) {
        info[p].apply(v);
        tag[p].apply(v);
    }

    void push(int p) {
        apply(2 * p, tag[p]);
        apply(2 * p + 1, tag[p]);
        tag[p] = Tag();
    }

    void rangeApply(int p, int l, int r, int x, int y, const Tag &v) {
        if (l > y || r < x) {
            return;
        }
        if (l >= x && r <= y) {
            apply(p, v);
            return;
        }
        push(p);
        int m = (l + r) / 2;
        rangeApply(2 * p, l, m, x, y, v);
        rangeApply(2 * p + 1, m + 1, r, x, y, v);
        pull(p);
    }

    void rangeApply(int l, int r, const Tag &v) {
        return rangeApply(1, 1, n, l, r, v);
    }

    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l > y || r < x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        push(p);
        int m = (l + r) / 2;
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m + 1, r, x, y);
    }

    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 1, n, l, r);
    }
};

struct Tag {
    LL x = 0;

    void apply(const Tag &t) {
        x += t.x;
    }
};

struct Info {
    LL x = 0, l, r;

    void apply(const Tag &t) {
        if (t.x) {
            x += t.x * (r - l + 1);
        }
    }
};

Info operator+(const Info &a, const Info &b) {
    return Info(a.x + b.x, a.l, b.r);
}

树状数组

template<typename T>
class FenwickTree {
  public:
	FenwickTree(int _n) : n(_n) {
		a.assign(n + 1, T());
	}

	void add(int x, T v) {
		for (int i = x; i <= n; i += i & -i) {
			a[i] += v;
		}
	}

	T sum(int x) {
		auto ans = T();
		for (int i = x; i > 0; i -= i & -i) {
			ans += a[i];
		}
		return ans;
	}

	T rangeSum(int l, int r) {
		return sum(r) - sum(l - 1);
	}
  private:
	int n;
	std::vector<T> a;
};

轻重链剖分

struct HLD {
    vector<vector<int>> e;
    vector<int> top, dep, parent, siz, son, id, a, val;
    int idx, mod;

    HLD(int n, int P) {
        mod = P;
        e.resize(n + 1);
        top.resize(n + 1);
        dep.resize(n + 1);
        parent.resize(n + 1);
        siz.resize(n + 1);
        son.resize(n + 1);
        id.resize(n + 1);
        idx = 0;
        a.resize(n + 1);
        val.resize(n + 1);
        tr.resize((n << 2) + 1);
    }

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

    void dfs1(int u) {
        siz[u] = 1;
        dep[u] = dep[parent[u]] + 1;
        for (auto v: e[u]) {
            if (v == parent[u]) continue;
            parent[v] = u;
            dfs1(v);
            siz[u] += siz[v];
            if (siz[v] > siz[son[u]]) son[u] = v;
        }
    }

    void dfs2(int u, int up) {
        id[u] = ++idx;
        top[u] = up;
        val[idx] = a[u];
        if (son[u]) dfs2(son[u], up);
        for (auto v: e[u]) {
            if (v == parent[u] || v == son[u]) continue;
            dfs2(v, v);
        }
    }

    void modifyRange(int u, int v, int k) {
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            modify(1, id[top[u]], id[u], k);
            u = parent[top[u]];
        }
        if (dep[u] > dep[v]) swap(u, v);
        modify(1, id[u], id[v], k);
    }

    LL queryRange(LL u, LL v) {
        LL ans = 0;
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            ans = (ans + query(1, id[top[u]], id[u])) % mod;
            u = parent[top[u]];
        }
        if (dep[u] > dep[v]) swap(u, v);
        return (ans + query(1, id[u], id[v])) % mod;
    }

    void modifySon(LL u, LL k) {
        modify(1, id[u], id[u] + siz[u] - 1, k);
    }

    LL querySon(LL u) {
        return query(1, id[u], id[u] + siz[u] - 1) % mod;
    }
};

dsu on tree

struct DsuOnTree {
    vector<vector<int>> adj;
    vector<int> siz, dep, dfn, idfn, son;
    int idx;

    DsuOnTree(int n) {
        adj.resize(n + 1);
        siz.resize(n + 1);
        dep.resize(n + 1);
        idx = 0;
        dfn.resize(n + 1);
        idfn.resize(n + 1);
        son.resize(n + 1);
    }

    void addEdge(int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    void dfs1(int u, int fa) {
        siz[u] = 1;
        dep[u] = dep[fa] + 1;
        dfn[u] = ++idx;
        idfn[idx] = u;
        for (auto v: adj[u]) {
            if (v == fa) continue;
            dfs1(v, u);
            siz[u] += siz[v];
            if (siz[v] > siz[son[u]]) son[u] = v;
        }
    }

    void dfs2(int u, int fa, int opt) {
        for (auto v: adj[u]) {
            if (v == fa || v == son[u]) continue;
            dfs2(v, u, 0);
        }
        if (son[u]) {
            dfs2(son[u], u, 1);
        }
        for (auto v: adj[u]) {
            if (v == fa || v == son[u]) continue;
            for (int i = dfn[v]; i <= dfn[v] + siz[v] - 1; i++) {
                int x = idfn[i];

            }
        }
        if (!opt) {
            for (int i = dfn[u]; i <= dfn[u] + siz[u] - 1; i++) {
                int x = idfn[i];

            }
        }
    }
};

并查集

struct DSU {
    vector<int> f, siz;

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

    int find(int x) {
        return x == f[x] ? x : (f[x] = find(f[x]));
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

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

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

ST表

struct SparseTable {
    int n;
    vector<int> a;
    vector<vector<int>> mx;

    SparseTable(int n) : n(n), a(n + 1), mx(n + 1, vector<int>(__lg(n) + 1)) {}

    void init() {
        for (int i = 1; i <= n; i++) {
            mx[i][0] = a[i];
        }
        int k = __lg(n);
        for (int j = 1; j <= k; j++) {
            for (int i = 1; i + (1 << j) - 1 <= n; i++) {
                mx[i][j] = max(mx[i][j - 1], mx[i + (1 << (j - 1))][j - 1]);
            }
        }
    }

    int queryMax(int L, int R) {
        int k = __lg(R - L + 1);
        return max(mx[L][k], mx[R - (1 << k) + 1][k]);
    }
};

可持久化线段树

struct PersistentTree {
    static constexpr int N = 2e5;
    int idx, root[N + 1];
    struct Node {
        int l, r;
        int info;
    } tr[N << 5];

    PersistentTree(vector<int> &a) {
        int n = a.size();
        idx = 0;
        function<int(int, int)> build = [&](int l, int r) {
            int p = ++idx;
            if (l == r) {
                tr[p].info = 0;
                return p;
            }
            int mid = (l + r) / 2;
            tr[p].l = build(l, mid);
            tr[p].r = build(mid + 1, r);
            return p;
        };
        root[0] = build(1, n);
    }

    int insert(int u, int l, int r, int x) {
        int v = ++idx;
        tr[v] = tr[u];
        tr[v].info++;
        if (l == r) return v;
        int mid = (l + r) / 2;
        if (x <= mid) tr[v].l = insert(tr[u].l, l, mid, x);
        else tr[v].r = insert(tr[u].r, mid + 1, r, x);
        return v;
    }

    int query(int u, int v, int l, int r, int k) {
        if (l == r) return l;
        int mid = (l + r) / 2;
        int x = tr[tr[v].l].info - tr[tr[u].l].info;
        if (k <= x) return query(tr[u].l, tr[v].l, l, mid, k);
        else return query(tr[u].r, tr[v].r, mid + 1, r, k - x);
    }
};

KDTree

struct KDT {
    constexpr static int K = 2;
    double alpha = 0.725;
    struct node {
        int info[K];
        int mn[K], mx[K];
    };
    vector<node> tr;
    vector<int> ls, rs, siz, id, d;
    int idx, rt, cur;
    int ans;

    KDT(int n) {
        tr.resize(n + 1);
        ls.resize(n + 1);
        rs.resize(n + 1);
        siz.resize(n + 1);
        id.resize(n + 1);
        d.resize(n + 1);
        rt = 0;
        cur = 0;
    }

    void apply(int p, int son) {
        if (son) {
            for (int i = 0; i < K; i++) {
                tr[p].mn[i] = min(tr[p].mn[i], tr[son].mn[i]);
                tr[p].mx[i] = max(tr[p].mx[i], tr[son].mx[i]);
            }
            siz[p] += siz[son];
        }
    }

    void maintain(int p) {
        for (int i = 0; i < K; i++) {
            tr[p].mn[i] = tr[p].info[i];
            tr[p].mx[i] = tr[p].info[i];
        }
        siz[p] = 1;
        apply(p, ls[p]);
        apply(p, rs[p]);
    }

    int build(int l, int r) {
        if (l > r) return 0;
        vector<double> avg(K);
        for (int i = 0; i < K; i++) {
            for (int j = l; j <= r; j++) {
                avg[i] += tr[id[j]].info[i];
            }
            avg[i] /= (r - l + 1);
        }
        vector<double> var(K);
        for (int i = 0; i < K; i++) {
            for (int j = l; j <= r; j++) {
                var[i] += (tr[id[j]].info[i] - avg[i]) * (tr[id[j]].info[i] - avg[i]);
            }
        }
        int mid = (l + r) / 2;
        int x = max_element(var.begin(), var.end()) - var.begin();
        nth_element(id.begin() + l, id.begin() + mid, id.begin() + r + 1, [&](int a, int b) {
            return tr[a].info[x] < tr[b].info[x];
        });
        d[id[mid]] = x;
        ls[id[mid]] = build(l, mid - 1);
        rs[id[mid]] = build(mid + 1, r);
        maintain(id[mid]);
        return id[mid];
    }

    void print(int p) {
        if (!p) return;
        print(ls[p]);
        id[++idx] = p;
        print(rs[p]);
    }

    void rebuild(int &p) {
        idx = 0;
        print(p);
        p = build(1, idx);
    }

    bool bad(int p) {
        return alpha * siz[p] <= max(siz[ls[p]], siz[rs[p]]);
    }

    void insert(int &p, int cur) {
        if (!p) {
            p = cur;
            maintain(p);
            return;
        }
        if (tr[p].info[d[p]] > tr[cur].info[d[p]]) insert(ls[p], cur);
        else insert(rs[p], cur);
        maintain(p);
        if (bad(p)) rebuild(p);
    }

    void insert(vector<int> &a) {
        cur++;
        for (int i = 0; i < K; i++) {
            tr[cur].info[i] = a[i];
        }
        insert(rt, cur);
    }

    bool out(int p, vector<int> &a) {
        for (int i = 0; i < K; i++) {
            if (a[i] < tr[p].mn[i]) {
                return true;
            }
        }
        return false;
    }

    bool in(int p, vector<int> &a) {
        for (int i = 0; i < K; i++) {
            if (a[i] < tr[p].info[i]) {
                return false;
            }
        }
        return true;
    }

    bool all(int p, vector<int> &a) {
        for (int i = 0; i < K; i++) {
            if (a[i] < tr[p].mx[i]) {
                return false;
            }
        }
        return true;
    }

    void query(int p, vector<int> &a) {
        if (!p) return;
        if (out(p, a)) return;
        if (all(p, a)) {
            ans += siz[p];
            return;
        }
        if (in(p, a)) ans++;
        query(ls[p], a);
        query(rs[p], a);
    }

    int query(vector<int> &a) {
        ans = 0;
        query(rt, a);
        return ans;
    }
};

字符串

kmp

std::vector<int> kmp(std::string s) {
	int n = s.size();
	std::vector<int> next(n + 1);
	for (int i = 1, j = 0; i < n; i++) {
		while (j > 0 && s[i] != s[j]) {
			j = next[j];
		}
		if (s[i] == s[j]) {
			j++;
		}
		next[i + 1] = j;
	}
	return next;
}

Z函数

vector<int> zFunction(string s) {
    int n = s.size();
    vector<int> z(n);
    z[0] = n;
    for (int i = 1, j = 1; i < n; i++) {
        z[i] = max(0, min(j + z[j] - i, z[i - j]));
        while (i + z[i] < n && s[z[i]] == s[i + z[i]]) {
            z[i]++;
        }
        if (i + z[i] > j + z[j]) {
            j = i;
        }
    }
    return z;
}

manacher

vector<int> manacher(string s) {
    string t = "-#";
    for (auto c: s) {
        t += c;
        t += '#';
    }
    int n = t.size();
    t += '+';
    vector<int> p(n);
    for (int i = 1, mid = 0, r = 0; i < n; i++) {
        p[i] = i < r ? min(p[2 * mid - i], r - i) : 1;
        while (t[i - p[i]] == t[i + p[i]]) p[i]++;
        if (i + p[i] > r) {
            r = i + p[i];
            mid = i;
        }
    }
    return p;
}

字典树

template<typename T>
class Trie {
  public:
	Trie(int n) {
		idx = 0;
		ch.resize(std::__lg(std::numeric_limits<T>::max()) * (n + 1), std::vector<int>(2));
	}

	int insert(T x) {
		int u = 0;
		for (int i = std::__lg(std::numeric_limits<T>::max()); ~i; i--) {
			int &v = ch[u][x >> i & 1];
			if (!v) v = ++idx;
			u = v;
		}
		return u;
	}

	T query(int x) {
		int u = 0;
		T res = T();
		for (int i = std::__lg(std::numeric_limits<T>::max()); ~i; i--) {
			int v = x >> i & 1;
			if (ch[u][!v]) {
				res += (T)1 << i;
				u = ch[u][!v];
			} else {
				u = ch[u][v];
			}
		}
		return res;
	}
  private:
	int idx;
	std::vector<std::vector<int>> ch;
};

AC自动机

Trie+Kmp,多模式串匹配

struct ACAutomaton {
    static constexpr int N = 1e6 + 1;
    int ch[N][26], fail[N], idx;
    int cnt[N];

    ACAutomaton() {
        idx = 0;
    }

    void insert(string s) {
        int u = 0;
        for (auto c: s) {
            int &v = ch[u][c - 'a'];
            if (!v) v = ++idx;
            u = v;
        }
        cnt[u]++;
    }

    void build() {
        queue<int> q;
        for (auto v: ch[0]) {
            if (v) {
                fail[v] = 0;
                q.push(v);
            }
        }
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < 26; i++) {
                int &v = ch[u][i];
                if (v) {
                    fail[v] = ch[fail[u]][i];
                    q.push(v);
                } else {
                    v = ch[fail[u]][i];
                }
            }
        }
    }

    int query(string t) {
        int u = 0;
        int ans = 0;
        for (auto c: t) {
            u = ch[u][c - 'a'];
            for (int v = u; v && ~cnt[v]; v = fail[v]) {
                ans += cnt[v];
                cnt[v] = -1;
            }
        }
        return ans;
    }
};

后缀自动机

有向无环图

struct SuffixAutomaton {
    static constexpr int N = 1e6;
    struct node {
        int len, link, nxt[26];
        int siz;
    } t[N << 1];
    int cntNodes;

    SuffixAutomaton() {
        cntNodes = 1;
        fill(t[0].nxt, t[0].nxt + 26, 1);
        t[0].len = -1;
    }

    int extend(int p, int c) {
        if (t[p].nxt[c]) {
            int q = t[p].nxt[c];
            if (t[q].len == t[p].len + 1) {
                return q;
            }
            int r = ++cntNodes;
            t[r].siz = 0;
            t[r].len = t[p].len + 1;
            t[r].link = t[q].link;
            copy(t[q].nxt, t[q].nxt + 26, t[r].nxt);
            t[q].link = r;
            while (t[p].nxt[c] == q) {
                t[p].nxt[c] = r;
                p = t[p].link;
            }
            return r;
        }
        int cur = ++cntNodes;
        t[cur].len = t[p].len + 1;
        t[cur].siz = 1;
        while (!t[p].nxt[c]) {
            t[p].nxt[c] = cur;
            p = t[p].link;
        }
        t[cur].link = extend(p, c);
        return cur;
    }
};

后缀数组

struct SuffixArray {
    int n;
    vector<int> sa, rk, lc;

    SuffixArray(const string &s) {
        n = s.size();
        sa.resize(n + 1);
        rk.resize(n + 1);
        int N = 127;
        vector<int> cnt(N + 1);
        for (int i = 1; i <= n; i++) {
            cnt[rk[i] = s[i - 1]]++;
        }
        for (int i = 1; i <= N; i++) {
            cnt[i] += cnt[i - 1];
        }
        for (int i = n; i >= 1; i--) {
            sa[cnt[rk[i]]--] = i;
        }
        vector<int> id(n + 1), tmp(n + 1), oldrk(n + 1);
        auto cmp = [&](int x, int y, int w) {
            return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w];
        };
        for (int w = 1, p, i;; w *= 2, N = p) {
            for (p = 0, i = n; i > n - w; i--) {
                id[++p] = i;
            }
            for (i = 1; i <= n; i++) {
                if (sa[i] > w) {
                    id[++p] = sa[i] - w;
                }
            }
            cnt.assign(N + 1, 0);
            for (i = 1; i <= n; i++) {
                cnt[tmp[i] = rk[id[i]]]++;
            }
            for (i = 1; i <= N; i++) {
                cnt[i] += cnt[i - 1];
            }
            for (i = n; i >= 1; i--) {
                sa[cnt[tmp[i]]--] = id[i];
            }
            oldrk = rk;
            for (p = 0, i = 1; i <= n; i++) {
                rk[sa[i]] = cmp(sa[i], sa[i - 1], w) ? p : ++p;
            }
            if (p == n) break;
        }
        lc.resize(n + 1);
        for (int i = 1, j = 0; i <= n; i++) {
            if (rk[i] == 0) continue;
            if (j) j--;
            while (s[i + j - 1] == s[sa[rk[i] - 1] + j - 1]) j++;
            lc[rk[i]] = j;
        }
    }
};

回文自动机

struct PalindromeAutomaton {
    vector<vector<int>> tr;
    vector<int> fail, len, cnt;
    int idx, last;

    PalindromeAutomaton(string s) {
        int n = s.size();
        tr.resize(n + 2, vector<int>(26));
        fail.resize(n + 2);
        len.resize(n + 2);
        cnt.resize(n + 2);
        len[0] = 0, fail[0] = 1;
        len[1] = -1, fail[1] = 0;
        idx = 1;
        last = 0;
        int k = 0;
        for (int i = 0; i < n; i++) {
            s[i] = (s[i] - 97 + k) % 26 + 'a';
            int u = last;
            while (i - len[u] - 1 < 0 || s[i - len[u] - 1] != s[i]) {
                u = fail[u];
            }
            if (!tr[u][s[i] - 'a']) {
                int v = ++idx;
                int t = fail[u];
                while (i - len[t] - 1 < 0 || s[i - len[t] - 1] != s[i]) {
                    t = fail[t];
                }
                fail[v] = tr[t][s[i] - 'a'];
                tr[u][s[i] - 'a'] = v;
                len[v] = len[u] + 2;
                cnt[v] = cnt[fail[v]] + 1;
            }
            last = tr[u][s[i] - 'a'];
            k = cnt[last];
            cout << k << " \n"[i == n - 1];
        }
    }
};

数学

取模整数型

template<class T>
constexpr T power(T a, LL b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {
            res *= a;
        }
    }
    return res;
}

template<int mod>
struct ModZ {
    LL x;

    constexpr ModZ(LL x = 0) : x(norm(x)) {}

    constexpr LL norm(LL x) { return (x % mod + mod) % mod; }

    constexpr ModZ inv() { return power(*this, mod - 2); }

    constexpr ModZ &operator*=(ModZ rhs) &{
        x = norm(x * rhs.x);
        return *this;
    }

    constexpr ModZ &operator+=(ModZ rhs) &{
        x = norm(x + rhs.x);
        return *this;
    }

    constexpr ModZ &operator-=(ModZ rhs) &{
        x = norm(x - rhs.x);
        return *this;
    }

    constexpr ModZ &operator/=(ModZ rhs) &{ return *this *= rhs.inv(); }

    friend constexpr ModZ operator*(ModZ lhs, ModZ rhs) {
        ModZ res = lhs;
        res *= rhs;
        return res;
    }

    friend constexpr ModZ operator+(ModZ lhs, ModZ rhs) {
        ModZ res = lhs;
        res += rhs;
        return res;
    }

    friend constexpr ModZ operator-(ModZ lhs, ModZ rhs) {
        ModZ res = lhs;
        res -= rhs;
        return res;
    }

    friend constexpr ModZ operator/(ModZ lhs, ModZ rhs) {
        ModZ res = lhs;
        res /= rhs;
        return res;
    }

    friend constexpr istream &operator>>(istream &is, ModZ &a) {
        LL v;
        is >> v;
        a = ModZ(v);
        return is;
    }

    friend constexpr ostream &operator<<(ostream &os, const ModZ &a) { return os << a.x; }

    friend constexpr bool operator==(ModZ lhs, ModZ rhs) { return lhs.x == rhs.x; }

    friend constexpr bool operator!=(ModZ lhs, ModZ rhs) { return lhs.x != rhs.x; }
};

constexpr int P = 998244353;
using Z = ModZ<P>;

组合数学

struct Combinatorics {
    vector<Z> fac, invfac;

    Combinatorics(int n) {
        fac.resize(n + 1);
        invfac.resize(n + 1);

        fac[0] = 1;
        for (int i = 1; i <= n; i++) {
            fac[i] = fac[i - 1] * i;
        }
        invfac[n] = fac[n].inv();
        for (int i = n - 1; i >= 0; i--) {
            invfac[i] = invfac[i + 1] * (i + 1);
        }
    }

    Z binom(int n, int m) {
        if (n < m || m < 0) return 0LL;
        return fac[n] * invfac[m] * invfac[n - m];
    }
};

快速傅里叶变换(FFT)

struct Polynomial {
    constexpr static double PI = acos(-1);

    struct Complex {
        double x, y;

        Complex(double _x = 0.0, double _y = 0.0) {
            x = _x;
            y = _y;
        }

        Complex operator-(const Complex &rhs) const { return Complex(x - rhs.x, y - rhs.y); }

        Complex operator+(const Complex &rhs) const { return Complex(x + rhs.x, y + rhs.y); }

        Complex operator*(const Complex &rhs) const { return Complex(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x); }
    };

    vector<Complex> c;

    Polynomial(vector<int> &a) {
        int n = a.size();
        c.resize(n);
        for (int i = 0; i < n; i++) {
            c[i] = Complex(a[i], 0);
        }
        fft(c, n, 1);
    }

    void change(vector<Complex> &a, int n) {
        for (int i = 1, j = n / 2; i < n - 1; i++) {
            if (i < j) swap(a[i], a[j]);
            int k = n / 2;
            while (j >= k) {
                j -= k;
                k /= 2;
            }
            if (j < k) j += k;
        }
    }

    void fft(vector<Complex> &a, int n, int opt) {
        change(a, n);
        for (int h = 2; h <= n; h *= 2) {
            Complex wn(cos(2 * PI / h), sin(opt * 2 * PI / h));
            for (int j = 0; j < n; j += h) {
                Complex w(1, 0);
                for (int k = j; k < j + h / 2; k++) {
                    Complex u = a[k];
                    Complex t = w * a[k + h / 2];
                    a[k] = u + t;
                    a[k + h / 2] = u - t;
                    w = w * wn;
                }
            }
        }
        if (opt == -1) {
            for (int i = 0; i < n; i++) {
                a[i].x /= n;
            }
        }
    }
};

快速数论变换(NTT)

struct Polynomial {
    vector<Z> z;
    vector<int> r;

    Polynomial(vector<int> &a) {
        int n = a.size();
        z.resize(n);
        r.resize(n);
        for (int i = 0; i < n; i++) {
            z[i] = a[i];
            r[i] = (i & 1) * (n / 2) + r[i / 2] / 2;
        }
        ntt(z, n, 1);
    }

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

    void ntt(vector<Z> &a, int n, int opt) {
        for (int i = 0; i < n; i++) {
            if (r[i] < i) {
                swap(a[i], a[r[i]]);
            }
        }
        for (int k = 2; k <= n; k *= 2) {
            Z gn = power(3, (mod - 1) / k);
            for (int i = 0; i < n; i += k) {
                Z g = 1;
                for (int j = 0; j < k / 2; j++, g *= gn) {
                    Z t = a[i + j + k / 2] * g;
                    a[i + j + k / 2] = a[i + j] - t;
                    a[i + j] = a[i + j] + t;
                }
            }
        }
        if (opt == -1) {
            reverse(a.begin() + 1, a.end());
            Z inv = power(n, mod - 2);
            for (int i = 0; i < n; i++) {
                a[i] *= inv;
            }
        }
    }
};

拉格朗日插值

struct Lagrange {
    int n;
    vector<Z> x, y, fac, invfac;

    Lagrange(int n) {
        this->n = n;
        x.resize(n + 3);
        y.resize(n + 3);
        fac.resize(n + 3);
        invfac.resize(n + 3);
        init(n);
    }

    void init(int n) {
        iota(x.begin(), x.end(), 0);
        for (int i = 1; i <= n + 2; i++) {
            Z t;
            y[i] = y[i - 1] + t.power(i, n);
        }
        fac[0] = 1;
        for (int i = 1; i <= n + 2; i++) {
            fac[i] = fac[i - 1] * i;
        }
        invfac[n + 2] = fac[n + 2].inv();
        for (int i = n + 1; i >= 0; i--) {
            invfac[i] = invfac[i + 1] * (i + 1);
        }
    }

    Z solve(LL k) {
        if (k <= n + 2) {
            return y[k];
        }
        vector<Z> sub(n + 3);
        for (int i = 1; i <= n + 2; i++) {
            sub[i] = k - x[i];
        }
        vector<Z> mul(n + 3);
        mul[0] = 1;
        for (int i = 1; i <= n + 2; i++) {
            mul[i] = mul[i - 1] * sub[i];
        }
        Z ans = 0;
        for (int i = 1; i <= n + 2; i++) {
            ans = ans + y[i] * mul[n + 2] * sub[i].inv() * pow(-1, n + 2 - i) * invfac[i - 1] * invfac[n + 2 - i];
        }
        return ans;
    }
};

扩展欧几里得

LL exgcd(LL a, LL b, LL &x, LL &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    LL d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

矩阵

struct Matrix {
    int n;
    vector<vector<Z>> a;

    Matrix(int n) {
        this->n = n;
        a.resize(n, vector<Z>(n));
    }

    Matrix mul(const Matrix &a, const Matrix &b) {
        Matrix res(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    res.a[i][j] += a.a[i][k] * b.a[k][j];
                }
            }
        }
        return res;
    }

    Matrix power(Matrix a, LL b) {
        Matrix res(n);
        for (int i = 0; i < n; i++) {
            res.a[i][i] = 1;
        }
        for (; b; b /= 2, a = mul(a, a)) {
            if (b % 2) {
                res = mul(res, a);
            }
        }
        return res;
    }
};

几何

const double eps = 1e-8;

struct point {
    double x, y;

    point operator+(const point &rhs) const { return point{x + rhs.x, y + rhs.y}; }

    point operator-(const point &rhs) const { return point{x - rhs.x, y - rhs.y}; }

    point operator*(double rhs) const { return point{x * rhs, y * rhs}; }

    point operator/(double rhs) const { return point{x / rhs, y / rhs}; }
};

using vec = point;

double cross(point p1, point p2) { return p1.x * p2.y - p1.y * p2.x; }  //叉乘

int sign(double k) {
    if (k > eps) return 1;
    else if (k < -eps) return -1;
    else return 0;
}

int parallel(point p1, point p2, point p3, point p4) { return sign(cross(p1 - p2, p3 - p4)) == 0; }  //平行

double dist(point p1, point p2) { return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); }  //两点间距离

point intersection(point p1, point p2, point p3, point p4) {  //两直线交点
    double w1 = cross(p1 - p2, p4 - p2);
    double w2 = -cross(p1 - p2, p3 - p2);
    return (p3 * w1 + p4 * w2) / (w1 + w2);
}

bool onSegment(point p, point s, point t) { return fabs(dist(p, s) + dist(p, t) - dist(s, t)) < eps; }  //点是否在线段上

double distPoint2Vector(point p1, vec v1, point p2, vec v2) {
    return cross(v2, p2 - p1) / cross(v1, v2);
}  //点 p1 到线段 v2 的距离

double intersectionPolygon(point A, point B) {  //线段 AB 与多边形的公共长度
    vector <pair<double, int>> pos;
    vec v = B - A;
    for (int i = 0; i < n; i++) {
        int sign1 = sign(cross(v, poly[i] - A));
        int sign2 = sign(cross(v, poly[(i + 1) % n] - A));
        if (sign1 == sign2) continue;
        double w = distPoint2Vector(A, v, poly[i], poly[(i + 1) % n] - poly[i]);
        pos.push_back({w, sign1 - sign2});
    }
    sort(pos.begin(), pos.end());
    double res = 0;
    int sum = 0;
    for (int i = 0; i < pos.size(); i++) {
        sum += pos[i].second;
        if (sum) {
            res += pos[i + 1].first - pos[i].first;
        }
    }
    return res * dist(A, B);
};

图论

最大流

template<typename T>
struct Flow {
    int n;
    vector<pair<int, T>> e;
    vector<vector<int>> g;
    vector<int> h, cur;

    Flow(int n) : n(n), g(n) {}

    void addEdge(int u, int v, T c) {
        g[u].push_back(e.size());
        e.emplace_back(v, c);
        g[v].push_back(e.size());
        e.emplace_back(u, 0);
    }

    bool bfs(int s, int t) {
        h.assign(n, -1);
        h[s] = 0;
        queue<int> q;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i: g[u]) {
                auto [v, c] = e[i];
                if (c > 0 && h[v] == -1) {
                    h[v] = h[u] + 1;
                    if (v == t) return true;
                    q.push(v);
                }
            }
        }
        return false;
    }

    T dfs(int u, int t, T f) {
        if (u == t) return f;
        auto r = f;
        for (int &i = cur[u]; i < g[u].size(); ++i) {
            int j = g[u][i];
            auto [v, c] = e[j];
            if (c > 0 && h[v] == h[u] + 1) {
                auto a = dfs(v, t, min(r, c));
                e[j].second -= a;
                e[j ^ 1].second += a;
                r -= a;
                if (r == 0) return f;
            }
        }
        return f - r;
    }

    T maxFlow(int s, int t) {
        T ans = 0;
        while (bfs(s, t)) {
            cur.assign(n, 0);
            ans += dfs(s, t, numeric_limits<T>::max());
        }
        return ans;
    }
};

珂朵莉树

struct ODT {
    struct node {
        int l, r;
        mutable LL v;

        node(int l, int r = -1, LL v = 0) : l(l), r(r), v(v) {}

        bool operator<(const node &o) const { return l < o.l; }
    };

    set<node> s;

    ODT() {
        s.clear();
    }

    auto split(int pos) {
        auto it = s.lower_bound(node(pos));
        if (it != s.end() && it->l == pos) return it;
        it--;
        int l = it->l, r = it->r;
        LL v = it->v;
        s.erase(it);
        s.insert(node(l, pos - 1, v));
        return s.insert(node(pos, r, v)).first;
    }

    void assign(int l, int r, LL x) {
        auto itr = split(r + 1), itl = split(l);
        s.erase(itl, itr);
        s.insert(node(l, r, x));
    }

    void add(int l, int r, LL x) {
        auto itr = split(r + 1), itl = split(l);
        for (auto it = itl; it != itr; it++) {
            it->v += x;
        }
    }

    LL kth(int l, int r, int k) {
        vector <pair<LL, int>> a;
        auto itr = split(r + 1), itl = split(l);
        for (auto it = itl; it != itr; it++) {
            a.push_back(pair<LL, int>(it->v, it->r - it->l + 1));
        }
        sort(a.begin(), a.end());
        for (auto [val, len]: a) {
            k -= len;
            if (k <= 0) return val;
        }
    }

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

    LL powersum(int l, int r, int x, int mod) {
        auto itr = split(r + 1), itl = split(l);
        LL ans = 0;
        for (auto it = itl; it != itr; it++) {
            ans = (ans + power(it->v, x, mod) * (it->r - it->l + 1) % mod) % mod;
        }
        return ans;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值