个人ACM封装模板(待持续补充)



前言


该篇文章创立旨意在于保存博主个人常用的一些模板,便于在遗忘时回顾查看,或者需要时方便回顾,思考到放在博客里可以反复查看,也更利于有需要的人学习使用,于是该博客就诞生了。

该博客的模板由于是博主个人归纳和总结的,所以可能不免会出现一些使用上的问题或者程序内的漏洞,如果存在此类漏洞,可以私信博主进行更改。

代码可以任意转载使用,遇到问题也可以私信博主。

代码为整合前人模板并将其修改成自使用版本,不保证均为博主自主钻研。



(1) BIT(树状数组)



template<typename T>
struct BIT {
    const int n;
    std::vector<T> tree;
    BIT(int n) : n(n), tree(n + 1) {};
    T Query(int x) {
        T res = 0;
        for (int i = x; i > 0; i -= (i & -i)) {
            res += tree[i];
        }
        return res;
    }
    void Modify(int l, T z) {
        if (l <= 0) return;
        for (int i = l; i <= n; i += (i & -i)) {
            tree[i] += z;
        }
    }
    T rangeQuery(int l, int r) {
        return Query(std::min(n, r)) - Query(std::max(0, l - 1));
    }
};

提交结果:P3374 【模板】树状数组 1
具体代码:具体代码

(2) Comb(组合数)



struct Comb {
    const int N;
    vector<i64> fac, invfac;
    Comb(int n) : N(n), fac(n + 2), invfac(n + 2) { init(); };
    i64 qpow(i64 x, i64 p) {
        i64 res = 1 % mod; x %= mod;
        for (; p; p >>= 1, x = x * x % mod)
            if (p & 1) res = res * x % mod;
        return res;
    }
    i64 inv(i64 x) { return qpow(x, mod - 2); };
    void init() {
        fac[0] = 1;
        for (int i = 1; i <= N; ++i) fac[i] = fac[i - 1] * i % mod;
        invfac[N] = inv(fac[N]);
        for (int i = N - 1; i >= 0; --i) invfac[i] = (invfac[i + 1] * (i + 1)) % mod;
    }
    i64 C(int n, int m) {
        if (n < m || m < 0) return 0;
        return fac[n] * invfac[m] % mod * invfac[n - m] % mod;
    }
    i64 A(int n, int m) {
        if (n < m || m < 0) return 0;
        return fac[n] * invfac[n - m] % mod;
    }
};

提交结果:F. Ira and Flamenco
具体代码:具体代码

(3) DSU(并查集)



struct DSU {
    vector<int> fa, siz;
    DSU(int n) : fa(n + 1), siz(n + 1, 1) { iota(fa.begin(), fa.end(), 0); };
    int find(int x) {
        while (x != fa[x]) x = fa[x] = fa[fa[x]];
        return x;
    }
    int size(int x) { return siz[find(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;
        siz[y] += siz[x];
        fa[x] = y;
        return true;
    }
};

提交结果:P3367 【模板】并查集
具体代码:具体代码

(4) HLD(重链剖分)




struct HLD {
    int n, idx;
    vector<int> siz, dep, fa;
    vector<int> dfn, rdfn, top;
    vector<vector<int>> g;

    HLD() {};
    HLD(int _) { init(_); }

    void init(int _) {
        this->n = _;
        dep.resize(_ + 1);
        fa.resize(_ + 1);
        dfn.resize(_ + 1);
        rdfn.resize(_ + 1);
        top.resize(_ + 1);
        siz.assign(_ + 1, 1);
        g.assign(_ + 1, {});
        idx = 0;
    }
    void addEdge(int u, int v) {
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    void DFS1(int u) {
        if (fa[u]) g[u].erase(find(g[u].begin(), g[u].end(), fa[u]));
        for (auto& v : g[u]) {
            fa[v] = u, dep[v] = dep[u] + 1;
            DFS1(v);
            siz[u] += siz[v];
            if (siz[v] > siz[g[u][0]]) {
                swap(v, g[u][0]);
            }
        }
    }
    void DFS2(int u) {
        dfn[u] = ++idx, rdfn[idx] = u;
        for (auto& v : g[u]) {
            top[v] = (v == g[u][0] ? top[u] : v);
            DFS2(v);
        }
    }
    int LCA(int u, int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            u = fa[top[u]];
        }
        return dep[u] < dep[v] ? u : v;
    }
    int findson(int u, int ufa) {
        int res;
        if (u == ufa) return u;
        if (dep[top[u]] < dep[top[ufa]]) swap(u, ufa);
        while (top[u] != top[ufa]) {
            res = top[u];
            u = fa[top[u]];
        }
        return u == ufa ? res : g[ufa][0];
    }
    int dist(int u, int v) {
        return dep[u] + dep[v] - (dep[LCA(u, v)] << 1);
    }
    int jump(int u, int k) {
        if (dep[u] < k) return -1;
        int d = dep[u] - k;
        while (dep[top[u]] > d) u = fa[top[u]];
        return rdfn[dfn[top[u]] - dep[top[u]] + d];
    }
    void work(int root = 1) {
        top[root] = root;
        dep[root] = 1;
        DFS1(root), DFS2(root);
    }
};

提交结果:P3379 【模板】最近公共祖先(LCA)
具体代码:具体代码

(5) Hungarian(匈牙利算法)



template<class BS>
struct Hungarian {
    int N1, N2;
    vector<BS> g;
    vector<int> match1, match2;
    vector<int> pre, que;
    BS vis;

    Hungarian(int n, int m) : N1(n), N2(m), g(n), match1(n), match2(m), pre(n), que(n) {}

    void BFS(int S) {
        int l = 0, r = 0;
        que[r++] = S, pre[S] = -1;
        vis.set();
        while (l < r) {
            int u = que[l++];
            auto adj = vis & g[u];
            for (int v = adj._Find_first(); v < N2; v = adj._Find_next(v)) {
                vis[v] = false;
                if (match2[v] != -1) {
                    que[r++] = match2[v];
                    pre[match2[v]] = u;
                    continue;
                }
                int x = u, y = v;
                while (x != -1) {
                    int t = match1[x];
                    match1[x] = y, match2[y] = x, x = pre[x], y = t;
                }
                return;
            }
        }
    }

    vector<PII> hungarian() {
        vector<PII> res;
        match1.assign(N1, -1);
        match2.assign(N2, -1);
        for (int i = 0; i < N1; ++i) {
            if (match1[i] == -1) BFS(i);
        }
        for (int i = 0; i < N1; ++i) {
            if (match1[i] != -1) res.emplace_back(i, match1[i]);
        }
        return res;
    }
};

提交结果:P3386 【模板】二分图最大匹配
具体代码:具体代码

(6) LazySegTree(懒标记线段树)




template<class Info, class Tag>
struct Segtree {
#define lson k << 1, l, mid
#define rson k << 1 | 1, mid + 1, r
    int n;
    vector<Info> info;
    vector<Tag> tag;
    Segtree(int _n) : n(_n), info((_n + 5) << 2), tag((_n + 5) << 2) {};
    Segtree(vector<Info>& arr) : Segtree(arr.size() - 1) {
        function<void(int, int, int)> build = [&](int k, int l, int r) {
            if (l == r) {
                info[k] = arr[l];
                return;
            }
            int mid = l + r >> 1;
            build(lson), build(rson);
            pushup(k);
        };
        build(1, 1, n);
    }
    void pushdown(int k, int l, int r) {
        int mid = l + r >> 1, lt = k << 1, rt = k << 1 | 1;
        info[lt].down(tag[k], mid - l + 1);
        info[rt].down(tag[k], r - mid);
        tag[lt].down(tag[k]);
        tag[rt].down(tag[k]);
        tag[k] = Tag();//初始化tag
    }
    void pushup(int k) {
        info[k] = merge(info[k << 1], info[k << 1 | 1]);
    }
    void Modify(int k, int l, int r, int x, int y, const Tag& z) {
        if (l >= x && r <= y) {
            info[k].down(z, r - l + 1);
            tag[k].down(z);
            return;
        }
        if (tag[k].change()) pushdown(k, l, r);
        int mid = l + r >> 1;
        if (x <= mid) Modify(lson, x, y, z);
        if (y > mid) Modify(rson, x, y, z);
        pushup(k);
    }
    Info Query(int k, int l, int r, int x, int y) {
        if (l >= x && r <= y) return info[k];
        if (tag[k].change()) pushdown(k, l, r);
        int mid = l + r >> 1;
        if (y <= mid) return Query(lson, x, y);
        if (x > mid) return Query(rson, x, y);
        return merge(Query(lson, x, y), Query(rson, x, y));
    }
    void Modify(int l, int r, const Tag& z) {
        Modify(1, 1, n, l, r, z);
    }
    Info Query(int l, int r) {
        return Query(1, 1, n, l, r);
    }
};

struct Tag {
    int val;
    bool change() { return val != 0; }
    void down(const Tag& t) {
        //标记下放
        val += t.val;
    }
};

struct Info {
    i64 sum;
    void down(const Tag& t, int len) {
        //标记下放
        sum += t.val * len;
    }
    friend Info merge(const Info& a, const Info& b) {
        Info res;
        res.sum = a.sum + b.sum;
        return res;
    }
};

Apply(l, r, Tag) 用Tag修改区间 [l, r]
Query(l, r) 返回区间 [l, r] 的Info信息

提交结果:P3372 【模板】线段树 1
具体代码:具体代码
提交结果:D. Andrey and Escape from Capygrad
具体代码:具体代码

(7) maxFlow(网络最大流)



template<class Ty>
struct maxFlow {
    const Ty INF = numeric_limits<Ty>::max();
    const int inf = INT32_MAX;
    int S, T, n; Ty MF = 0;
    struct Edge {
        int v, nxt; Ty f;
        Edge() : Edge(0, 0, 0) {};
        Edge(int v, int nxt, Ty f) : v(v), nxt(nxt), f(f) {};
    };

    vector<int> dist, cur, h;
    vector<Edge> E;

    maxFlow(int _) : n(_) { init(_); };

    void init(int _) {
        dist.resize(_ + 1);
        cur.resize(_ + 1);
        h.resize(_ + 1);
        E.resize(2);
    }

    void add(int u, int v, Ty f) {
        E.emplace_back(v, h[u], f), h[u] = int(E.size()) - 1;
    }

    void addEdge(int u, int v, Ty f) {
        add(u, v, f), add(v, u, 0);
    }

    bool BFS() {
        dist.assign(n + 1, inf);
        queue<int> que;
        dist[S] = 0, cur[S] = h[S];
        que.push(S);
        while (que.size()) {
            int u = que.front(); que.pop();
            for (int i = h[u]; i; i = E[i].nxt) {
                auto& [v, nxt, f] = E[i];
                if (f && dist[v] > dist[u] + 1) {
                    dist[v] = dist[u] + 1;
                    cur[v] = h[v];
                    if (v == T) return true;
                    que.push(v);
                }
            }
        }
        return false;
    }

    Ty DFS(int u, Ty flow) {
        if (u == T) return flow;
        Ty last = flow;
        for (int i = cur[u]; i && last; i = E[i].nxt) {
            cur[u] = i;
            auto& [v, nxt, f] = E[i];
            if (f && dist[v] == dist[u] + 1) {
                Ty cost = DFS(v, min(f, last));
                if (!cost) dist[v] = INF;
                E[i].f -= cost, E[i ^ 1].f += cost;
                last -= cost;
            }
        }
        return flow - last;
    }

    void work() {
        while (BFS()) {
            Ty flow = DFS(S, INF);
            MF += flow;
        }
    }
};

提交结果:P3376 【模板】网络最大流
具体代码:具体代码

(8) MCmaxFlow(最小费用最大流-SPFA)



template<class Ty>
struct MCmaxFlow {
    const Ty INF = numeric_limits<Ty>::max();
    int S, T, n; Ty MF = 0, MC = 0;
    struct Edge {
        int v, nxt; Ty f, w;
        Edge() : Edge(0, 0, 0, 0) {};
        Edge(int v, int nxt, Ty f, Ty w) : v(v), nxt(nxt), f(f), w(w) {};
    };

    vector<Ty> dist;
    vector<int> cur, h;
    vector<bool> vis;
    vector<Edge> E;

    MCmaxFlow(int _) : n(_) { init(_); };

    void init(int _) {
        dist.resize(_ + 1);
        vis.resize(_ + 1);
        cur.resize(_ + 1);
        h.resize(_ + 1);
        E.resize(2);
    }

    void add(int u, int v, Ty f, Ty w) {
        E.emplace_back(v, h[u], f, w), h[u] = int(E.size()) - 1;
    }

    void addEdge(int u, int v, Ty f, Ty w) {
        add(u, v, f, w), add(v, u, 0, -w);
    }

    bool SPFA() {
        dist.assign(n + 1, INF);
        queue<int> que;
        dist[S] = 0, cur[S] = h[S];
        que.push(S);
        while (que.size()) {
            int u = que.front(); que.pop();
            vis[u] = false;
            for (int i = h[u]; i; i = E[i].nxt) {
                auto& [v, nxt, f, w] = E[i];
                if (f && dist[v] > dist[u] + w) {
                    dist[v] = dist[u] + w;
                    if (!vis[v]) {
                        vis[v] = true;
                        cur[v] = h[v];
                        que.push(v);
                    }
                }
            }
        }
        return dist[T] != INF;
    }

    Ty DFS(int u, Ty flow) {
        if (u == T) return flow;
        Ty last = flow;
        vis[u] = true;
        for (int i = cur[u]; i && last; i = E[i].nxt) {
            cur[u] = i;
            auto& [v, nxt, f, w] = E[i];
            if (f && !vis[v] && dist[v] == dist[u] + w) {
                Ty cost = DFS(v, min(f, last));
                if (!cost) dist[v] = INF;
                E[i].f -= cost, E[i ^ 1].f += cost;
                last -= cost;
            }
        }
        vis[u] = false;
        return flow - last;
    }

    void work() {
        while (SPFA()) {
            Ty flow = DFS(S, INF);
            MC += dist[T] * flow;
            MF += flow;
        }
    }
};

提交结果:P3381 【模板】最小费用最大流
具体代码:具体代码

(9) RoundSquareTree(圆方树)



struct RoundSquareTree {
    int n, VDCC, idx;
    vector<vector<int>> g;
    vector<int> dfn, low, stk;
    vector<PII> edges;

    RoundSquareTree() {}
    RoundSquareTree(int _) { init(_); }

    void init(int _) {
        this->n = _;
        g.assign(_ + 1, {});
        dfn.resize(_ + 1);
        low.resize(_ + 1);
        edges.clear();
        stk.clear();
        VDCC = idx = 0;
    }
    void addEdge(int u, int v) {
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    void Tarjan(int u) {
        dfn[u] = low[u] = ++idx;
        stk.emplace_back(u);
        for (auto& v : g[u]) {
            if (!dfn[v]) {
                Tarjan(v);
                low[u] = min(low[u], low[v]);
                if (low[v] >= dfn[u]) {
                    ++VDCC; int top = -1;
                    while (top != v) {
                        top = stk.back(); stk.pop_back();
                        edges.emplace_back(top, n + VDCC);
                    }
                    edges.emplace_back(u, n + VDCC);
                }
            } else {
                low[u] = min(low[u], dfn[v]);
            }
        }
    }
    pair<int, vector<PII>> work() {
        for (int i = 1; i <= n; ++i) {
            if (!dfn[i]) {
                Tarjan(i);
                stk.clear();
            }
        }
        return {VDCC, edges};
    }
};

提交结果:P5236 【模板】静态仙人掌
具体代码:具体代码

(10) SCC(强连通分量/缩点)



struct SCC {
    int n, c_scc, idx;
    vector<int> stk;
    vector<int> dfn, low, scc, siz;
    vector<vector<int>> g;

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

    void init(int _) {
        this->n = _;
        g.assign(_ + 1, {});
        dfn.resize(_ + 1);
        low.resize(_ + 1);
        scc.resize(_ + 1);
        siz.resize(1);
        stk.clear();
        idx = c_scc = 0;
    }
    void addEdge(int u, int v) {
        g[u].emplace_back(v);
    }
    void DFS(int u) {
        dfn[u] = low[u] = ++idx;
        stk.emplace_back(u);
        for (auto& v : g[u]) {
            if (!dfn[v]) {
                DFS(v);
                low[u] = min(low[u], low[v]);
            }
            else if (!scc[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (dfn[u] == low[u]) {
            int top = -1, cnt = 0; ++c_scc;
            while (top != u) {
                top = stk.back(); stk.pop_back();
                scc[top] = c_scc; ++cnt;
            }
            siz.emplace_back(cnt);
        }
    }
    void work() {
        for (int i = 1; i <= n; ++i) {
            if (!dfn[i]) DFS(i);
        }
    }
};

提交结果:B3609 【模板】强连通分量
具体代码:具体代码

(11) Segtree(普通线段树 单点修改/区间查询)



template<class Info>
struct Segtree {
#define lson k << 1, l, mid
#define rson k << 1 | 1, mid + 1, r
    int n;
    vector<Info> info;
    Segtree(int _n) : n(_n), info((_n + 5) << 2) {};
    Segtree(vector<Info>& arr) : Segtree(arr.size() - 1) {
        function<void(int, int, int)> build = [&](int k, int l, int r) {
            if (l == r) {
                info[k] = arr[l];
                return;
            }
            int mid = l + r >> 1;
            build(lson), build(rson);
            pushup(k);
        };
        build(1, 1, n);
    }
    void pushup(int k) {
        info[k] = merge(info[k << 1], info[k << 1 | 1]);
    }
    void Modify(int k, int l, int r, int x, Info& z) {
        if (l == r) return void(info[k] = z);
        int mid = l + r >> 1;
        if (x <= mid) Modify(lson, x, z);
        if (x > mid) Modify(rson, x, z);
        pushup(k);
    }
    Info Query(int k, int l, int r, int x, int y) {
        if (l >= x && r <= y) return info[k];
        int mid = l + r >> 1;
        if (y <= mid) return Query(lson, x, y);
        if (x > mid) return Query(rson, x, y);
        return merge(Query(lson, x, y), Query(rson, x, y));
    }
    void Modify(int pos, Info& z) {
        Modify(1, 1, n, pos, z);
    }
    Info Query(int l, int r) {
        return Query(1, 1, n, l, r);
    }
};

struct Info {
    int sum;
    friend Info merge(const Info& a, const Info& b) {
        Info res;
        res.sum = a.sum + b.sum;
        return res;
    }
};

提交结果:P1198 [JSOI2008] 最大数
具体代码:具体代码
提交结果:E. Character Blocking
具体代码:具体代码

(12) ChthollyTree(珂朵莉树)



struct ChthollyTree {
    struct Node {
        i64 l, r;
        mutable i64 v;
        Node(i64 l, i64 r, i64 v) : l(l), r(r), v(v) {}
        bool operator<(const Node& t) const { return l < t.l; };
    };
    set<Node> ODT;

    set<Node>::iterator split(i64 pos) {
        auto it = ODT.lower_bound(Node(pos, 0, 0));
        if (it != ODT.end() && it->l == pos) return it;
        i64 l = (--it)->l, r = it->r, v = it->v;
        ODT.erase(it); ODT.emplace(l, pos - 1, v);
        return ODT.emplace(pos, r, v).first;
    }
    void push(int l, int r, i64 v) {
        ODT.emplace(l, r, v);
    }
    void assign(i64 l, i64 r, i64 v) {
        auto end = split(r + 1), begin = split(l);
        ODT.erase(begin, end);
        ODT.emplace(l, r, v);
    }
    void rangeadd(i64 l, i64 r, i64 v) {
        auto end = split(r + 1);
        for (auto it = split(l); it != end; ++it) {
            it->v += v;
        }
    }
    i64 qpow(i64 a, i64 b, i64 MOD) {
        i64 res = 1 % MOD; a %= MOD;
        for (; b; b >>= 1, a = a * a % MOD) {
            if (b & 1) res = res * a % MOD;
        }
        return res;
    }
    i64 rangepow(i64 l, i64 r, i64 x, i64 MOD) {
        i64 res = 0;
        auto end = split(r + 1);
        for (auto it = split(l); it != end; ++it) {
            res = (res + qpow(it->v, x, MOD) * (it->r - it->l + 1)) % MOD;
        }
        return res;
    }
    i64 kth(i64 l, i64 r, i64 k) {
        auto end = split(r + 1);
        vector<pair<i64, i64>> rnk;
        for (auto it = split(l); it != end; ++it) {
            rnk.emplace_back(it->v, it->r - it->l + 1);
        }
        sort(rnk.begin(), rnk.end());//第k大则改为greater
        int rnksz = rnk.size();
        for (int i = 0; i < rnksz; ++i) {
            k -= rnk[i].second;
            if (k <= 0) return rnk[i].first;
        }
        return -1;
    }
};

提交结果:C. Willem, Chtholly and Seniorious
具体代码:具体代码

(13) DSU2(带权并查集)



struct DSU2 {
    vector<int> fa, siz;
    vector<i64> dis;
    DSU2(int n) : fa(n + 1), siz(n + 1, 1), dis(n + 1) { iota(fa.begin(), fa.end(), 0); };
    function<int(int)> find = [&](int x) {
        if (x == fa[x]) return x;
        find(fa[x]); dis[x] += dis[fa[x]];
        return fa[x] = fa[fa[x]];
    };
    int size(int x) { return siz[find(x)]; }
    i64 dist(int x, int y) {
        int xf = find(x), yf = find(y);
        if (xf != yf) return -1;
        return dis[x] + -dis[y];
    }
    bool same(int x, int y) { return find(x) == find(y); }
    bool merge(int x, int y, i64 w) {
        int xf = find(x), yf = find(y);
        if (xf == yf) return false;
        siz[yf] += siz[xf]; fa[xf] = yf;
        dis[xf] = -dis[x] + w + dis[y];
        return true;
    }
};

提交结果:E. Building Forest
具体代码:具体代码


(14) ModInt(取模类模板)


template <int T>
struct MInt {
    constexpr static int MD = T;
    int x;
    MInt() : x(0) {}
    MInt(int _) : x(norm(_ % MD)) {}
    MInt(i64 _) : x(norm(_ % MD)) {}
    MInt(double _) : MInt(i64(_)) {}
    constexpr int norm(int a) const {
        if (a >= MD) a = a - MD;
        if (a < 0) a = a + MD;
        return a;
    }
    constexpr int get() const { return x; }
    constexpr MInt operator+(const MInt& that) const {
        return MInt(norm(x + that.x));
    }
    constexpr MInt operator-(const MInt& that) const {
        return MInt(norm(x - that.x));
    }
    constexpr MInt operator*(const MInt& that) const {
        return MInt((i64)x * that.x % MD);
    }
    constexpr MInt operator-() const { return MInt(norm(-x)); }
    constexpr MInt operator/(const MInt& that) const {
        assert(that.x != 0);
        return *this * that.inverse();
    }
    constexpr MInt inverse() const {
        int a = x, b = MD, u = 1, v = 0;
        while (b) {
            int t = a / b;
            std::swap(a -= t * b, b);
            std::swap(u -= t * v, v);
        }
        return norm(u);
    }
    void operator+=(const MInt& that) { x = norm(x + that.x); }
    void operator-=(const MInt& that) { x = norm(x - that.x); }
    void operator*=(const MInt& that) { x = norm((i64)x * that.x % MD); }
    void operator/=(const MInt& that) { *this = *this / that; }
    void operator--() { x = norm(x - 1); }
    void operator++() { x = norm(x + 1); }
    friend constexpr bool operator<(const MInt& A, const MInt& B) { return A.get() < B.get(); }
    friend constexpr bool operator>(const MInt& A, const MInt& B) { return A.get() > B.get(); }
    friend constexpr bool operator<=(const MInt& A, const MInt& B) { return A.get() <= B.get(); }
    friend constexpr bool operator>=(const MInt& A, const MInt& B) { return A.get() >= B.get(); }
    friend constexpr bool operator==(const MInt& A, const MInt& B) { return A.get() == B.get(); }
    friend constexpr bool operator!=(const MInt& A, const MInt& B) { return A.get() != B.get(); }
    friend constexpr std::istream& operator>>(istream &is, MInt& A) {
        i64 v; is >> v;
        A = MInt(v); return is;
    }
    friend constexpr std::ostream& operator<<(ostream& os, const MInt& x) {
        return os << x.get();
    }
};
constexpr int mod = 1e9 + 7;
using Mint = MInt<mod>;

提交结果:G. Counting Shortcuts
具体代码:具体代码


(15) Trie(动态开点Trie)


//自定义第二维长度
template <const int M>
struct Trie {
    vector<array<int, M>> trie;
    vector<bool> exist;
    vector<int> cnt;

    Trie() { init(); }
    void init() {
        trie.emplace_back(array<int, M>{});
        exist.resize(1);
        cnt.resize(1);
    }
    void insert(const string& str) {
        int now = 0, p;
        for (auto& c : str) {
            p = Pos(c);
            if (!trie[now][p]) {
                trie[now][p] = trie.size();
                trie.emplace_back(array<int, M>{});
                exist.emplace_back(false);
                cnt.emplace_back(0);
            }
            now = trie[now][p];
            ++cnt[now];
        }
        exist[now] = true;
    }
    int Querypre(const string& str) {
        int now = 0, p;
        for (auto& c : str) {
            p = Pos(c);
            if (!trie[now][p]) {
                return 0;
            }
            now = trie[now][p];
        }
        return cnt[now];
    }
    bool Querystr(const string& str) {
        int now = 0, p;
        for (auto& c : str) {
            p = Pos(c);
            if (!trie[now][p]) {
                return false;
            }
            now = trie[now][p];
        }
        return exist[now];
    }
    int Pos(char ch) {
    	//自定义位置参数
        if (ch >= 'a' && ch <= 'z') return ch - 'a';
        if (ch >= 'A' && ch <= 'Z') return ch - 'A' + 26;
        if (ch >= '0' && ch <= '9') return ch - '0' + 52;
    }
};

提交结果:【模板】字典树
具体代码:具体代码


(16) SparseTable(ST表)


template <class Ty, const int logn>
struct SparseTable {
    vector<array<Ty, logn>> info;

    SparseTable(const vector<Ty>& A) { init(A); }
    void init(const vector<Ty>& A) {
        int n = A.size() - 1;
        info.assign(A.size(), array<Ty, logn>{});
        for (int i = 1; i <= n; ++i) {
            info[i][0] = A[i];
        }
        for (int j = 1; j <= logn; ++j) {
            for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
                info[i][j] = merge(info[i][j - 1], info[i + (1 << j - 1)][j - 1]);
            }
        }
    }
    Ty Query(int l, int r) {
        int j = __lg(r - l + 1);
        return merge(info[l][j], info[r - (1 << j) + 1][j]);
    };
    constexpr Ty merge(const Ty& a, const Ty& b) {
    	//自定义信息合并方式
        return max(a, b);
    }
};

提交结果:【模板】ST 表
具体代码:具体代码


(17) CartesianTree(笛卡尔树)


template<class Ty>
struct CartesianTree {
    vector<int> stk;
    vector<int> L, R;
    CartesianTree() {}
    tuple<int, vector<int>, vector<int>> work(const vector<Ty>& A) {
        L.assign(A.size(), 0), R.assign(A.size(), 0);
        int n = A.size() - 1;
        for (int i = 1; i <= n; ++i) {
            int lst = 0;
            while (stk.size() && A[stk.back()] > A[i]) {
                lst = stk.back();
                stk.pop_back();
            }
            if (stk.size()) {
                R[stk.back()] = i;
            }
            if (lst) {
                L[i] = lst;
            }
            stk.emplace_back(i);
        }
        return {stk[0], L, R};
    }
};

提交结果:【模板】笛卡尔树
具体代码:具体代码


(18) Basis(线性基)


template<class Ty, const int M>
struct Basis {
    Ty a[M] {};
    bool insert(Ty x) {
        for (Ty i = M - 1; i >= 0; --i) {
            if (x >> i & 1) {
                if (!a[i]) return a[i] = x, true;
                x ^= a[i];
            }
        }
        return false;
    }
    bool check(Ty x) {
        for (Ty i = M - 1; i >= 0; --i) {
            if (x >> i & 1) x ^= a[i];
        }
        return x == 0;
    }
    Ty Query() {
        Ty res = 0;
        for (Ty i = M - 1; i >= 0; --i) {
            res = max(res, res ^ a[i]);
        }
        return res;
    }
};

提交结果:【模板】线性基
具体代码:具体代码


(19) BlockArray(块状数组)


template<class T>
struct BlockArray {
    i64 Len, Bnum;
    vector<T> info;
    vector<int> pos, L, R;
    BlockArray(const vector<T>& a) { init(a); }

    void init(const vector<T>& a) {
        int N = a.size() - 1;
        Len = sqrt(N);
        Bnum = (N + Len - 1) / Len;
        pos.resize(N + 1);
        L.resize(Bnum + 1);
        R.resize(Bnum + 1);
        info.resize(Bnum + 1);
        for (int i = 1; i <= Bnum; ++i) {
            L[i] = R[i - 1] + 1, R[i] = i * Len;
        }
        R[Bnum] = N;
        for (int i = 1; i <= Bnum; ++i) {
            for (int j = L[i]; j <= R[i]; ++j) {
                pos[j] = i;
                //处理信息
            }
        }
    }

    void Modify(int l, int r) {
        int lb = pos[l], rb = pos[r];
        if (lb == rb) {
            for (int i = l; i <= r; ++i) {
                //块内
            }
            return;
        }
        //整散块
        for (int i = lb + 1; i <= rb - 1; ++i) {

        }
        for (int i = l; i <= R[lb]; ++i) {

        }
        for (int i = r; i >= L[rb]; --i) {

        }
    }

    T Query(int l, int r) {
        int lb = pos[l], rb = pos[r];
        T res;
        if (lb == rb) {
            for (int i = l; i <= r; ++i) {
                //块内
            }
            return res;
        }
        //整散块
        for (int i = lb + 1; i <= rb - 1; ++i) {

        }
        for (int i = l; i <= R[lb]; ++i) {

        }
        for (int i = r; i >= L[rb]; --i) {

        }
        return res;
    }
};

提交结果:None.
具体代码:None.


(20) StringHash(字符串哈希)


template<const int N>
struct StringHash {
    using i64 = long long;
    using PII = std::pair<int, int>;
    const int mod1 = 1e9 + 97, mod2 = 998244853, p1 = 131, p2 = 233;
    std::array<int, N> a1, a2;
    std::array<int, N> Phs1, Phs2;
    std::array<int, N> Shs1, Shs2;//如果不判回文 删掉后缀哈希可以减小一半常数
    StringHash() {
        init(N - 1);
    }
    StringHash(const std::string& S) {
        init(N - 1);
        work(S);
    }
    // All of the Working progress is 0-idxed [0, 1, 2, ..., n - 1]
    void work(const std::string& s) {
        int n = s.size();
        assert(n + 1 <= N);
        for (int i = 0; i < n; ++i) {
            int t = n - i - 1;
            Phs1[i + 1] = ((i64)Phs1[i] * p1 + s[i]) % mod1;
            Phs2[i + 1] = ((i64)Phs2[i] * p2 + s[i]) % mod2;
            Shs1[t + 1] = ((i64)Shs1[t + 2] * p1 + s[t]) % mod1;//如果不判回文 删掉后缀哈希可以减小一半常数
            Shs2[t + 1] = ((i64)Shs2[t + 2] * p2 + s[t]) % mod2;//如果不判回文 删掉后缀哈希可以减小一半常数
        }
    }
    // All of the Query is 1-idxed [1, 2, 3, ..., n]
    PII PreHash(int l, int r) {
        assert(l <= r);
        int P1 = (Phs1[r] - (i64)Phs1[l - 1] * a1[r - l + 1] % mod1 + mod1) % mod1;
        int P2 = (Phs2[r] - (i64)Phs2[l - 1] * a2[r - l + 1] % mod2 + mod2) % mod2;
        return PII(P1, P2);
    };
    PII SufHash(int l, int r) {
        assert(l <= r);
        int S1 = (Shs1[l] - (i64)Shs1[r + 1] * a1[r - l + 1] % mod1 + mod1) % mod1;
        int S2 = (Shs2[l] - (i64)Shs2[r + 1] * a2[r - l + 1] % mod2 + mod2) % mod2;
        return PII(S1, S2);
    }
    bool isPlalindrome(int l, int r) {
        auto [P1, P2] = PreHash(l, r);
        auto [S1, S2] = SufHash(l, r);
        return P1 == S1 && P2 == S2;
    }
    void init(int n) {
        a1[0] = a2[0] = 1;
        for (int i = 0; i < n; ++i) {
            a1[i + 1] = (i64)a1[i] * p1 % mod1;
            a2[i + 1] = (i64)a2[i] * p2 % mod2;
        }
    }
};

提交结果:【模板】字符串哈希
具体代码:具体代码


(21) MincostFlow(最小费用最大流-原始对偶)



template<class Ty>
struct MincostFlow {
    const Ty INF = numeric_limits<Ty>::max();
    const int n;
    struct Edge {
        int v, nxt; Ty f, w;
        Edge() : Edge(0, 0, 0, 0) {};
        Edge(int v, int nxt, Ty f, Ty w) : v(v), nxt(nxt), f(f), w(w) {};
    };
    struct mypair {
        Ty dist; int u;
        mypair() : mypair(0, 0) {}
        mypair(Ty d, int u) : dist(d), u(u) {}
        bool operator<(const mypair& rhs) const {
            return dist > rhs.dist;
        }
    };
    int S, T; Ty MF = 0, MC = 0;
    vector<Ty> dist, D;
    vector<int> h, pre;
    vector<Edge> E;

    MincostFlow(int _) : n(_) { init(_); };

    void init(int _) {
        h.resize(_ + 1, -1);
        dist.resize(_ + 1);
        pre.resize(_ + 1);
        D.resize(_ + 1);
    }
    void add(int u, int v, Ty flow, Ty weight) {
        E.emplace_back(v, h[u], flow, weight), h[u] = int(E.size()) - 1;
    }
    void addEdge(int u, int v, Ty f, Ty w) {
        add(u, v, f, w), add(v, u, 0, -w);
    }

    bool dijkstra() {
        dist.assign(n + 1, INF);
        priority_queue<mypair> q;
        dist[S] = 0;
        q.emplace(0, S);
        while (q.size()) {
            auto [dis, u] = q.top(); q.pop();
            if (dist[u] < dis) continue;
            for (int i = h[u]; ~i; i = E[i].nxt) {
                auto& [v, nxt, f, w] = E[i];
                if (f > 0 && dist[v] > dis + D[u] - D[v] + w) {
                    dist[v] = dis + D[u] - D[v] + w;
                    q.emplace(dist[v], v);
                    pre[v] = i;
                }
            }
        }
        return dist[T] != INF;
    }
    void work() {
        while (dijkstra()) {
            Ty flow = INF;
            for (int i = 0; i <= n; ++i) D[i] += dist[i];
            for (int i = T; i != S; i = E[pre[i] ^ 1].v) flow = min(flow, E[pre[i]].f);
            for (int i = T; i != S; i = E[pre[i] ^ 1].v) {
                E[pre[i]].f -= flow, E[pre[i] ^ 1].f += flow;
            }
            MC += D[T] * flow;
            MF += flow;
        }
    }
};

(22) FHQTreap(FHQ-Treap平衡树)



struct FHQTreap {
#define L(x) T[x].l
#define R(x) T[x].r
    struct Node {
        int l, r, val, siz;
        std::mt19937::result_type key;
    };
    std::mt19937 rng;
    std::vector<Node> T;
    int idx, root;
    FHQTreap(int n) : T(n + 1), rng(std::chrono::steady_clock::now().time_since_epoch().count()) {
        root = idx = 0;
    }
    int creat(const int& val) {
        return T[++idx] = {0, 0, val, 1, rng()}, idx;
    }
    void pushup(int& rt) {
        T[rt].siz = T[L(rt)].siz + T[R(rt)].siz + 1;
    }
    void splitV(int rt, int& l, int& r, const int& val) {
        if (!rt) return l = r = 0, void();
        if (T[rt].val >= val) {
            r = rt, splitV(L(rt), l, L(rt), val);
        } else {
            l = rt, splitV(R(rt), R(rt), r, val);
        }
        pushup(rt);
    }
    void splitR(int rt, int& l, int& r, const int& val) {
        if (!rt) return l = r = 0, void();
        if (T[L(rt)].siz >= val) {
            r = rt, splitR(L(rt), l, L(rt), val);
        } else {
            l = rt, splitR(R(rt), R(rt), r, val - T[L(rt)].siz - 1);
        }
        pushup(rt);
    }
    int merge(int l, int r) {
        if (!l || !r) return l | r;
        if (T[l].key < T[r].key) {
            return T[l].r = merge(T[l].r, r), pushup(l), l;
        } else {
            return T[r].l = merge(l, T[r].l), pushup(r), r;
        }
    }
    void insert(const int& val) {
        int l, r; splitV(root, l, r, val);
        root = merge(merge(l, creat(val)), r);
    }
    void erase(const int& val) {
        int l, m, r;
        splitV(root, l, m, val), splitR(m, m, r, 1);
        if (T[m].val == val) m = 0;
        root = merge(merge(l, m), r);
    }
    int rank(const int& val) {
        int l, r; splitV(root, l, r, val);
        int res = T[l].siz + 1;
        return root = merge(l, r), res;
    }
    int kth(const int& val) {
        int l, m, r;
        splitR(root, l, m, val - 1), splitR(m, m, r, 1);
        int res = T[m].val;
        return root = merge(merge(l, m), r), res;
    }
    bool contains(const int& val) {
        int rt = root;
        while (rt) {
            if (T[rt].val == val) {
                return true;
            }
            rt = T[rt].val > val ? L(rt) : R(rt);
        }
        return false;
    }
    int prev(const int& val) {
        return kth(rank(val) - 1);
    }
    int next(const int& val) {
        return kth(rank(val + 1));
    }
};

提交结果:P3369 【模板】普通平衡树
具体代码:具体代码

(23) Pollard-Rho/Miller-Rabbin(质因子分解/判素数)



i64 mul(i64 a, i64 b, i64 m) {
    return static_cast<__int128>(a) * b % m;
}
i64 power(i64 a, i64 b, i64 m) {
    i64 res = 1 % m;
    for (; b; b >>= 1, a = mul(a, a, m))
        if (b & 1)
            res = mul(res, a, m);
    return res;
}
bool isprime(i64 n) {
    if (n < 2)
        return false;
    static constexpr int A[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
    int s = __builtin_ctzll(n - 1);
    i64 d = (n - 1) >> s;
    for (auto a : A) {
        if (a == n)
            return true;
        i64 x = power(a, d, n);
        if (x == 1 || x == n - 1)
            continue;
        bool ok = false;
        for (int i = 0; i < s - 1; ++i) {
            x = mul(x, x, n);
            if (x == n - 1) {
                ok = true;
                break;
            }
        }
        if (!ok)
            return false;
    }
    return true;
}
std::vector<i64> factorize(i64 n) {
    std::vector<i64> p;
    auto f = [&](auto self, i64 n) {
        if (n <= 10000) {
            for (int i = 2; i * i <= n; ++i)
                for (; n % i == 0; n /= i)
                    p.push_back(i);
            if (n > 1)
                p.push_back(n);
            return;
        }
        if (isprime(n)) {
            p.push_back(n);
            return;
        }
        auto g = [&](i64 x) {
            return (mul(x, x, n) + 1) % n;
        };
        i64 x0 = 2;
        while (true) {
            i64 x = x0;
            i64 y = x0;
            i64 d = 1;
            i64 power = 1, lam = 0;
            i64 v = 1;
            while (d == 1) {
                y = g(y);
                ++lam;
                v = mul(v, std::abs(x - y), n);
                if (lam % 127 == 0) {
                    d = std::gcd(v, n);
                    v = 1;
                }
                if (power == lam) {
                    x = y;
                    power *= 2;
                    lam = 0;
                    d = std::gcd(v, n);
                    v = 1;
                }
            }
            if (d != n) {
                self(self, d);
                self(self, n / d);
                return;
            }
            ++x0;
        }
    };
    f(f, n);
    std::sort(p.begin(), p.end());
    return p;
}

提交结果:P4718 【模板】Pollard-Rho
具体代码:具体代码

(24) SAM(后缀自动机)



struct SAM {
    static constexpr int ALPHABET_SIZE = 26;
    struct Node {
        int len, link, cnt;
        std::array<int, ALPHABET_SIZE> next;
        Node() : len{}, cnt{}, link{}, next{} {}
    };
    std::vector<Node> T;
    SAM() { init(); }
    // Node ranges -> [1, size]
    void init() {
        T.assign(2, Node());
    }
    int newNode() {
        T.emplace_back();
        return (int)T.size() - 1;
    }
    int extend(int p, int c) {
        int lst = p;
        p = newNode();
        lenth(p) = lenth(lst) + 1; count(p) = 1;
        for (; lst && !next(lst, c); lst = link(lst)) {
            next(lst, c) = p;
        }
        if (lst == 0) {
            link(p) = 1;
        } else {
            int u = next(lst, c);
            if (lenth(lst) + 1 == lenth(u)) {
                link(p) = u;
            } else {
                int v = newNode();
                T[v].next = T[u].next;
                link(v) = link(u);
                link(u) = link(p) = v;
                lenth(v) = lenth(lst) + 1;
                for (; lst && next(lst, c) == u; lst = link(lst)) {
                    next(lst, c) = v;
                }
            }
        }
        return p;
    }
    int& link(int p) {
        return T[p].link;
    }
    int& lenth(int p) {
        return T[p].len;
    }
    int& next(int p, int c) {
        return T[p].next[c];
    }
    int& count(int p) {
        return T[p].cnt;
    }
    int size() {
        return (int)T.size() - 1;
    }
};

提交结果:P3804 【模板】后缀自动机(SAM)
具体代码:具体代码
提交结果:P6139 【模板】广义后缀自动机(广义 SAM)
具体代码:具体代码

(25) GSAM(广义后缀自动机)



struct GSAM {
    static constexpr int ALPHABET_SIZE = 26;
    struct Node {
        int len, link, cnt;
        std::array<int, ALPHABET_SIZE> next;
        Node() : len{}, cnt{}, link{}, next{} {}
    };
    std::vector<Node> T;
    GSAM() { init(); }
    // Node ranges -> [1, size]
    void init() {
        T.assign(2, Node());
    }
    int newNode() {
        T.emplace_back();
        return (int)T.size() - 1;
    }
    int extend(int p, int c) {
        if (next(p, c) && lenth(next(p, c)) == lenth(p) + 1) {
            return next(p, c);
        }
        int lst = p;
        p = newNode();
        lenth(p) = lenth(lst) + 1; count(p) = 1;
        for (; lst && !next(lst, c); lst = link(lst)) {
            next(lst, c) = p;
        }
        if (lst == 0) {
            link(p) = 1;
        } else {
            int u = next(lst, c);
            if (lenth(lst) + 1 == lenth(u)) {
                link(p) = u;
            } else {
                if (lenth(lst) + 1 == lenth(p)) {
                    T.pop_back();
                    p = -1;
                }
                int v = newNode();
                T[v].next = T[u].next;
                link(v) = link(u);
                link(u) = v;
                lenth(v) = lenth(lst) + 1;
                for (; lst && next(lst, c) == u; lst = link(lst)) {
                    next(lst, c) = v;
                }
                if (p == -1) {
                    return v;
                } else {
                    link(p) = v;
                }
            }
        }
        return p;
    }
    int& link(int p) {
        return T[p].link;
    }
    int& lenth(int p) {
        return T[p].len;
    }
    int& next(int p, int c) {
        return T[p].next[c];
    }
    int& count(int p) {
        return T[p].cnt;
    }
    int size() {
        return (int)T.size() - 1;
    }
};

提交结果:P6139 【模板】广义后缀自动机(广义 SAM)
具体代码:具体代码

(26) ACAM(AC自动机)



struct ACAM {
    static constexpr int ALPHABET_SIZE = 26;
    struct Node {
        int len, link, cnt;
        std::array<int, ALPHABET_SIZE> next;
        Node() : len{}, cnt{}, link{}, next{} {}
    };
    std::vector<Node> T;
    // Node ranges -> [0, size]
    ACAM() { init(); }
    void init() {
        T.assign(1, Node());
    }
    int newNode() {
        T.emplace_back();
        return (int)T.size() - 1;
    }
    int extend(const std::string& s) {
        int p = 0;
        for (auto& c : s) {
            int v = c - 'a';
            if (next(p, v) == 0) {
                next(p, v) = newNode();
                lenth(next(p, v)) = lenth(p) + 1;
            }
            p = next(p, v);
        }
        ++count(p);
        return p;
    }
    void work() {
        std::queue<int> q;
        for (int i = 0; i < ALPHABET_SIZE; ++i) {
            if (next(0, i)) {
                q.emplace(next(0, i));
            }
        }
        while (q.size()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < ALPHABET_SIZE; ++i) {
                if (next(u, i) == 0) {
                    next(u, i) = next(link(u), i);
                } else {
                    link(next(u, i)) = next(link(u), i);
                    q.emplace(next(u, i));
                }
            }
        }
    }
    int& link(int p) {
        return T[p].link;
    }
    int& lenth(int p) {
        return T[p].len;
    }
    int& next(int p, int c) {
        return T[p].next[c];
    }
    int& count(int p) {
        return T[p].cnt;
    }
    int size() {
        return (int)T.size() - 1;
    }
};

提交结果:P5357 【模板】AC 自动机
具体代码:具体代码

(27) rollDSU(回滚并查集)



struct rollDSU {
    std::vector<int> fa, siz;
    std::vector<std::tuple<int&, int&, int, int>> H;
    rollDSU(int n) : fa(n + 1), siz(n + 1, 1) { iota(fa.begin(), fa.end(), 0); };
    int find(int x) {
        while (x != fa[x]) x = fa[x];
        return x;
    }
    int size(int x) { return siz[find(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 (siz[x] > siz[y]) {
            std::swap(x, y);
        }
        H.emplace_back(fa[x], siz[y], fa[x], siz[y]);
        siz[y] += siz[x];
        fa[x] = y;
        return true;
    }
    void roll(int V) {
        while (H.size() > V) {
            auto [a, b, c, d] = H.back();
            a = c, b = d;
            H.pop_back();
        }
    }
    int version() {
        return H.size();
    }
};

提交结果:P5787 二分图 /【模板】线段树分治
具体代码:具体代码



  • update:2023 / 09 / 05 创建
  • update:2023 / 09 / 07 更新:DSU2(带权并查集)
  • update:2023 / 09 / 14 更新:ModInt(取模类模板)
  • update:2023 / 11 / 27 更新:Trie(动态开点Trie) / SparseTable(ST表)
  • update:2023 / 11 / 27 更新:顺带更新了一部分较老板子
  • update:2023 / 12 / 19 更新:CartesianTree(笛卡尔树)
  • update:2024 / 02 / 20 更新:Basis(线性基)/ BlockArray(块状数组)/ StringHash(字符串哈希)
  • update:2024 / 02 / 26 更新:MincostFlow(最小费用最大流-原始对偶)
  • update:2024 / 04 / 24 更新:FHQTreap(FHQ-Treap平衡树) / Pollard-Rho/Miller-Rabbin(质因子分解/判素数) / SAM(后缀自动机)
  • update:2024 / 05 / 15 更新:GSAM(广义后缀自动机) / ACAM(AC自动机) / rollDSU(回滚并查集)
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柠檬味的橙汁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值