专栏文章

模板

算法·理论参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miq72h7r
此快照首次捕获于
2025/12/04 00:01
3 个月前
此快照最后确认于
2025/12/04 00:01
3 个月前
查看原文

Min25 筛

CPP
// This Code was made by Chinese_zjc_.
template <class T>
struct array
{
    std::vector<T> f, g;
    array(long long n) : f(int(std::sqrt(n)) + 5), g(int(std::sqrt(n)) + 5) {}
    T &operator[](const long long &x) { return x * x <= n ? f[x] : g[n / x]; }
};
std::vector<long long> p;
bool isnp[100005];
void work(long long n)
{
    for (int i = 2; i <= 100000; ++i)
    {
        if (!isnp[i])
            p.push_back(i);
        for (auto j : p)
        {
            if (i * j > 100000)
                break;
            isnp[i * j] = true;
            if (i % j == 0)
                break;
        }
    }
    std::vector<long long> pos;
    for (long long i = 1; i * i <= n; ++i)
        pos.push_back(i), pos.push_back(n / i);
    std::sort(pos.begin(), pos.end());
    pos.erase(std::unique(pos.begin(), pos.end()), pos.end());
    array<std::vector<mint>> primes(n);
    auto getprimes = [&](long long x, int y)
    {
        if (p[y] > x)
            return mint(1);
        return y < int(primes[x].size()) ? primes[x][y] : primes[x].back() + (primes[x].size() - 1) - y;
    };
    for (auto i : pos)
    {
        primes[i].push_back(i);
        for (int j = 0; p[j] * p[j] <= i; ++j)
            primes[i].push_back(primes[i][j] - getprimes(i / p[j], j));
    }
    array<std::vector<mint>> dp;
    auto getdp = [&](long long x, int y)
    {
        return y < int(dp[x].size()) ? dp[x][y] : (getprimes(x, y) - 1) * val(1) + val(0);
    };
    for (auto i : pos)
    {
        dp[i].resize(primes[i].size());
        dp[i].back() = (primes[i].back() - 1) * val(1) + val(0);
        for (int j = dp[i].size() - 1; j--;)
            for (long long k = 0, l = 1; l <= i; ++k, l *= p[j])
                dp[i][j] += getdp(i / l, j + 1) * val(k);
    }
    return dp[n][0];
}

AC自动机

CPP
void build(int pos){
    scanf("%s",s+1);
    int len=strlen(s+1);
    int now=0;
    for (int i=1;i<=len;i++){
        if (a[now].son[s[i]-'a']==0)a[now].son[s[i]-'a']=++cnt;
        now=a[now].son[s[i]-'a'];
        if (i==len)a[now].pos.push_back(pos);
    }
    return;
}
int head,tail,q[200005];
void getfail(){
    head=1,tail=0;
    for (int i=0;i<26;i++)
        if (a[0].son[i])q[++tail]=a[0].son[i];
    while(head<=tail){
        int now=q[head];
        head++;
        for (int i=0;i<26;i++){
            if (a[now].son[i]){
                a[a[now].son[i]].fail=a[a[now].fail].son[i];
                q[++tail]=a[now].son[i];
            }
            else a[now].son[i]=a[a[now].fail].son[i];
        }
    }
    return;
}
void work(){
    int now=0;
    for (int i=1;i<=n;i++){
        now=a[now].son[s[i]-'a'];
        size[now]++;
    }
    return;
}
void dfs(int now){
    for (int i=first[now];i;i=nxt[i]){
        dfs(v[i]);
        size[now]+=size[v[i]];
    }
    for (int len=a[now].pos.size(),j=0;j<len;j++)
        ans[a[now].pos[j]]+=size[now];
    return;
}

Z函数

CPP
for (int i=2;i<=m;i++){
    if (i<=r)z[i]=min(z[i-l+1],r-i+1);
    while(i+z[i]<=m&&b[i+z[i]]==b[z[i]+1])z[i]++;
    if (i+z[i]-1>r)l=i,r=i+z[i]-1;
}

Manacher

CPP
n=strlen(x+1);
a[++len]='$';
for (int i=1;i<=n;i++)a[++len]=x[i],a[++len]='$';
int l=0,r=0;
for (int i=1;i<=len;i++){
    if (i<=r)mc[i]=min(r-i+1,mc[l+r-i]);
    while(i-mc[i]>=1&&i+mc[i]<=len&&a[i-mc[i]]==a[i+mc[i]])mc[i]++;
    if (i+mc[i]-1>=r)l=i-mc[i]+1,r=i+mc[i]-1;
    lt[i]=(i-mc[i]+2)/2,rt[i]=(i+mc[i]-2)/2;
    ans=max(ans,rt[i]-lt[i]+1);
}

回文自动机

CPP
struct pam_node{
    int son[27],len,link,ans;
    pam_node(){
        memset(son,0,sizeof(son));
        len=link=0;
        return;
    }
}pam[1000005];
int cnt;
int n,ans;
char s[1000005];
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    cnt=1;
    pam[0].len=-1,pam[0].link=-1;
    pam[1].len=0,pam[1].link=0;
    int last=0;
    for (int i=1;i<=n;i++){        
        s[i]=(s[i]-97+ans)%26+97;
        int p=last;
        while(p!=-1&&s[i]!=s[i-1-pam[p].len])p=pam[p].link;
        if (pam[p].son[s[i]-'a']!=0){
            int now=pam[p].son[s[i]-'a'];
            last=now;
        }
        else{
            int now=++cnt;
            pam[now].len=pam[p].len+2;
            pam[p].son[s[i]-'a']=now;
            last=now;
            int qwq=pam[p].link;
            while(qwq!=-1&&s[i]!=s[i-1-pam[qwq].len])qwq=pam[qwq].link;
            if (qwq==-1)pam[now].link=1;
            else pam[now].link=pam[qwq].son[s[i]-'a'];
        }
        pam[last].ans=pam[pam[last].link].ans+1;
        ans=pam[last].ans;
        printf("%d ",ans);
    }
    return 0;
}

后缀自动机

CPP
int sam_ins(char x){
    int p=last;
    int now=++sam_cnt;
    sam[now].len=sam[p].len+1;
    while(p!=-1&&sam[p].son[x-'a']==0){
        sam[p].son[x-'a']=now;
        p=sam[p].link;
    }
    if (p==-1){
        sam[now].link=0;
        last=now;
        return now;
    }
    int q=sam[p].son[x-'a'];
    if (sam[q].len==sam[p].len+1){
        sam[now].link=q;
        last=now;
        return now;
    }
    int clone=++sam_cnt;
    sam[clone]=sam[q];
    sam[clone].len=sam[p].len+1;
    sam[now].link=sam[q].link=clone;
    while(p!=-1&&sam[p].son[x-'a']==q){
        sam[p].son[x-'a']=clone;
        p=sam[p].link;
    }
    last=now;
    return now;
}

后缀数组

SAIS

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
void SAIS(int *s, int *sa, int n, int m)
{
    static const bool S = false, L = true;
    bool t[n];
    t[n - 1] = S;
    for (int i = n - 1; i--;)
        if (s[i] < s[i + 1])
            t[i] = S;
        else if (s[i] > s[i + 1])
            t[i] = L;
        else
            t[i] = t[i + 1];
    auto lms = [&](const int &x)
    { return x > 0 && t[x - 1] == L && t[x] == S; };
    auto equal = [&](int A, int B)
    {
        do
        {
            if (s[A] != s[B] || t[A] != t[B])
                return false;
            ++A;
            ++B;
        } while (!(lms(A) || lms(B)));
        return s[A] == s[B] && t[A] == t[B];
    };
    std::vector<int> g;
    for (int i = 0; i != n; ++i)
        if (lms(i))
            g.push_back(i);
    int sum[m + 1], *p[m];
    std::fill(sum, sum + m + 1, 0);
    for (int i = 0; i != n; ++i)
        ++sum[s[i] + 1];
    for (int i = 1; i <= m; ++i)
        sum[i] += sum[i - 1];
    std::fill(sa, sa + n, -1);
    for (int i = 0; i != m; ++i)
        p[i] = sa + sum[i + 1];
    for (int i : g)
        *--p[s[i]] = i;
    for (int i = 0; i != m; ++i)
        p[i] = sa + sum[i];
    for (int i = 0; i != n; ++i)
        if (sa[i] > 0 && t[sa[i] - 1] == L)
            *p[s[sa[i] - 1]]++ = sa[i] - 1;
    for (int i = 0; i != m; ++i)
        p[i] = sa + sum[i + 1];
    for (int i = n; i--;)
        if (sa[i] > 0 && t[sa[i] - 1] == S)
            *--p[s[sa[i] - 1]] = sa[i] - 1;
    int tmp[n], M = -1;
    for (int i = 0, lst = -1; i != n; ++i)
        if (lms(sa[i]))
            tmp[sa[i]] = ~lst && equal(lst, sa[i]) ? M : ++M, lst = sa[i];
    int h[g.size()];
    if (++M == int(g.size()))
        for (int i : g)
            h[tmp[i]] = i;
    else
    {
        int ns[g.size()];
        for (int i = 0; i != int(g.size()); ++i)
            ns[i] = tmp[g[i]];
        SAIS(ns, h, g.size(), M);
        for (int &i : h)
            i = g[i];
    }
    std::reverse(h, h + g.size());
    std::fill(sa, sa + n, -1);
    for (int i = 0; i != m; ++i)
        p[i] = sa + sum[i + 1];
    for (int i : h)
        *--p[s[i]] = i;
    for (int i = 0; i != m; ++i)
        p[i] = sa + sum[i];
    for (int i = 0; i != n; ++i)
        if (sa[i] > 0 && t[sa[i] - 1] == L)
            *p[s[sa[i] - 1]]++ = sa[i] - 1;
    for (int i = 0; i != m; ++i)
        p[i] = sa + sum[i + 1];
    for (int i = n; i--;)
        if (sa[i] > 0 && t[sa[i] - 1] == S)
            *--p[s[sa[i] - 1]] = sa[i] - 1;
}
signed main()
{
    std::ios::sync_with_stdio(false);
    std::string sss;
    int s[1000005], sa[1000005];
    std::cin >> sss;
    std::copy(sss.begin(), sss.end(), s);
    s[sss.size()] = 0;
    SAIS(s, sa, sss.size() + 1, 128);
    for (std::size_t i = 1; i <= sss.size(); ++i)
        std::cout << sa[i] + 1 << " \n"[i == sss.size()];
    return 0;
}

经典倍增

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
int n, m, q, sa[1000005], rk[1000005], sum[1000005], height[1000005];
char s[1000005];
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin >> (s + 1);
    n = std::strlen(s + 1);
    m = 128;
    for (int i = 1; i <= n; ++i)
        ++sum[rk[i] = s[i]];
    for (int i = 1; i <= m; ++i)
        sum[i] += sum[i - 1];
    for (int i = n; i; --i)
        sa[sum[rk[i]]--] = i;
    for (int k = 1; k <= n; k <<= 1)
    {
        static int cnt, tmp[1 << 20 | 5];
        cnt = 0;
        for (int i = n - k + 1; i <= n; ++i)
            tmp[++cnt] = i;
        for (int i = 1; i <= n; ++i)
            if (sa[i] > k)
                tmp[++cnt] = sa[i] - k;
        std::fill(sum + 1, sum + 1 + m, 0);
        for (int i = 1; i <= n; ++i)
            ++sum[rk[i]];
        for (int i = 1; i <= m; ++i)
            sum[i] += sum[i - 1];
        for (int i = n; i; --i)
            sa[sum[rk[tmp[i]]]--] = tmp[i];
        std::copy(rk + 1, rk + 1 + n, tmp + 1);
        rk[sa[1]] = m = 1;
        for (int i = 2; i <= n; ++i)
            rk[sa[i]] = tmp[sa[i]] == tmp[sa[i - 1]] && tmp[sa[i] + k] == tmp[sa[i - 1] + k] ? m : ++m;
        if (n == m)
            break;
    }
    for (int i = 1; i <= n; ++i)
        std::cout << sa[i] << " \n"[i == n];
    return 0;
}

Link-Cut Tree(链上异或和)

CPP
// This Code was made by Chinese_zjc_.
int n, m;
template <class Type>
class LCT
{
private:
    class node
    {
    public:
        Type val, sum;
        int son[2], fa;
        bool rev;
        node() : val(), sum(), son(), fa() {}
        node(Type val_) : val(val_), sum(val_), son(), fa() {}
        void clear()
        {
            val = sum = Type();
            son[0] = son[1] = fa = 0;
        }
    } tree[100005];

public:
    LCT() {}
    void pushup(int now) { tree[now].sum = tree[now].val ^ tree[tree[now].son[0]].sum ^ tree[tree[now].son[1]].sum; }
    void pushdown(int now)
    {
        if (tree[now].rev)
        {
            std::swap(tree[now].son[0], tree[now].son[1]);
            tree[tree[now].son[0]].rev ^= true;
            tree[tree[now].son[1]].rev ^= true;
            tree[now].rev = false;
        }
    }
    void init_splay(int now)
    {
        if (~query_son(now))
            init_splay(tree[now].fa);
        pushdown(now);
    }
    int query_son(int now)
    {
        int fa = tree[now].fa, res = 2;
        while (res--)
            if (tree[fa].son[res] == now)
                break;
        return res;
    }
    void connect(int A, int B, int which)
    {
        if (A && ~which)
            tree[A].son[which] = B;
        if (B)
            tree[B].fa = A;
    }
    void rotate(int now)
    {
        int fa = tree[now].fa;
        bool nowg = query_son(now);
        connect(tree[fa].fa, now, query_son(fa));
        connect(fa, tree[now].son[!nowg], nowg);
        connect(now, fa, !nowg);
        pushup(fa);
    }
    void splay(int now)
    {
        init_splay(now);
        for (int fa = tree[now].fa; ~query_son(now); rotate(now), fa = tree[now].fa)
            if (query_son(fa) == query_son(now))
                rotate(fa);
    }
    void access(int now)
    {
        for (int lst = 0; now; lst = now, now = tree[now].fa)
        {
            splay(now);
            tree[now].son[1] = lst;
            pushup(now);
        }
    }
    void reverse(int now) { tree[now].rev ^= true; }
    void make_root(int now)
    {
        access(now);
        splay(now);
        reverse(now);
    }
    int find_root(int now)
    {
        access(now);
        splay(now);
        for (pushdown(now); tree[now].son[0]; pushdown(now))
            now = tree[now].son[0];
        splay(now);
        return now;
    }
    void split(int A, int B)
    {
        make_root(A);
        access(B);
        splay(B);
    }
    bool link(int A, int B)
    {
        make_root(A);
        int root = find_root(B);
        if (A == root)
            return false;
        make_root(B);
        tree[B].fa = A;
        access(B);
        return true;
    }
    bool cut(int A, int B)
    {
        split(A, B);
        if (tree[B].son[0] != A || tree[A].son[1])
            return false;
        tree[A].fa = tree[B].son[0] = 0;
        pushup(B);
        return true;
    }
    int sum(int A, int B)
    {
        split(A, B);
        pushup(B);
        return tree[B].sum;
    }
    void modify(int pos, int val)
    {
        splay(pos);
        tree[pos].val = val;
        pushup(pos);
    }
    void _visit(int now = 0)
    {
        if (!now)
        {
            for (int i = 1; i <= n; ++i)
                if (!~query_son(i))
                    _visit(i);
            return;
        }
        if (tree[now].son[0])
            _visit(tree[now].son[0]);
        if (tree[now].fa)
            std::cout << "   " << tree[now].fa << ' ' << now << ' ' << query_son(now) << std::endl;
        if (tree[now].son[1])
            _visit(tree[now].son[1]);
    }
};
LCT<int> lct;
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin >> n >> m;
    for (int i = 1; i <= n; ++i)
    {
        static int x;
        std::cin >> x;
        lct.modify(i, x);
    }
    for (int i = 1; i <= m; ++i)
    {
        static int opt, x, y;
        std::cin >> opt >> x >> y;
        switch (opt)
        {
        case 0:
            std::cout << lct.sum(x, y) << std::endl;
            break;
        case 1:
            lct.link(x, y);
            break;
        case 2:
            lct.cut(x, y);
            break;
        case 3:
            lct.modify(x, y);
            break;
        }
    }
    return 0;
}

多项式(+,,×,1,xddx,dxx+,-,\times,^{-1},\frac{x\operatorname{d}}{\operatorname{d}x},\int\frac{\operatorname{d}x}{x}

CPP
// This Code was made by Chinese_zjc_.
namespace answer
{
    const unsigned MOD = 998244353;
    struct mint
    {
        unsigned v;
        mint(unsigned v_ = 0) : v(v_) {}
        mint operator-() const { return v ? MOD - v : *this; }
        mint &operator+=(const mint &X) { return (v += X.v) >= MOD ? v -= MOD : v, *this; }
        mint &operator-=(const mint &X) { return (v += MOD - X.v) >= MOD ? v -= MOD : v, *this; }
        mint &operator*=(const mint &X) { return v = 1llu * v * X.v % MOD, *this; }
        mint &operator/=(const mint &X) { return *this *= X.inv(); }
        mint pow(long long B) const
        {
            B %= MOD - 1;
            if (B < 0)
                B += MOD - 1;
            mint res = 1, A = *this;
            while (B)
            {
                if (B & 1)
                    res *= A;
                B >>= 1;
                A *= A;
            }
            return res;
        }
        mint inv() const { return pow(MOD - 2); }
        friend mint operator+(const mint &A, const mint &B) { return mint(A) += B; }
        friend mint operator-(const mint &A, const mint &B) { return mint(A) -= B; }
        friend mint operator*(const mint &A, const mint &B) { return mint(A) *= B; }
        friend mint operator/(const mint &A, const mint &B) { return mint(A) /= B; }
        friend std::istream &operator>>(std::istream &A, mint &B) { return A >> B.v; }
        friend std::ostream &operator<<(std::ostream &A, const mint &B) { return A << B.v; }
        friend bool operator==(const mint &A, const mint &B) { return A.v == B.v; }
        explicit operator bool() const { return v; }
    } fact[200005], ifact[200005], inv[200005], d[200005], id[200005], x, y, xn, yn, h[100005];
    std::vector<mint> omega[19];
    mint Cn(int m) { return 0 <= m ? d[m] * ifact[m] : 0; }
    mint iCn(int m) { return 0 <= m ? id[m] * fact[m] : 0; }
    mint C(int n, int m) { return 0 <= m && m <= n ? fact[n] * ifact[m] * ifact[n - m] : 0; }
    mint iC(int n, int m) { return 0 <= m && m <= n ? ifact[n] * fact[m] * fact[n - m] : 0; }
    typedef std::vector<mint> poly;
    int n, ra, rb, m;
    void init()
    {
        fact[0] = 1;
        for (int i = 1; i <= 200000; ++i)
            fact[i] = fact[i - 1] * i;
        ifact[200000] = fact[200000].inv();
        for (int i = 200000; i; --i)
            ifact[i - 1] = ifact[i] * i;
        for (int i = 1; i <= 200000; ++i)
            inv[i] = ifact[i] * fact[i - 1];
        d[0] = 1;
        for (int i = 0; i != 200000; ++i)
            d[i + 1] = d[i] * (n - i);
        for (int i = 0; i <= 200000; ++i)
            id[i] = d[i].inv();
        xn = x.pow(n);
        yn = y.pow(n);
        for (int i = 0; i <= 18; ++i)
        {
            mint w = mint(3).pow((MOD - 1) >> i >> 1);
            omega[i].resize(1 << i);
            omega[i][0] = 1;
            for (int j = 1; j != 1 << i; ++j)
                omega[i][j] = omega[i][j - 1] * w;
        }
    }
    void NTT(poly &X)
    {
        static std::vector<std::size_t> rev;
        if (rev.size() != X.size())
        {
            rev.resize(X.size());
            for (std::size_t i = 0; i != rev.size(); ++i)
                rev[i] = (rev[i >> 1] | (i & 1 ? rev.size() : 0)) >> 1;
        }
        for (std::size_t i = 0; i != X.size(); ++i)
            if (i < rev[i])
                std::swap(X[i], X[rev[i]]);
        unsigned long long v[X.size()];
        for (std::size_t i = 0; i != X.size(); ++i)
            v[i] = X[i].v;
        for (std::size_t i = 1, l = 0; i != X.size(); i <<= 1, ++l)
        {
            for (std::size_t j = 0; j != X.size(); j += i << 1)
            {
                for (std::size_t k = 0; k != i; ++k)
                {
                    unsigned long long A = v[j + k], B = v[i + j + k] * omega[l][k].v % MOD;
                    v[j + k] = A + B;
                    v[i + j + k] = A + MOD - B;
                }
            }
            if (i == 262144)
                for (std::size_t i = 0; i != X.size(); ++i)
                    v[i] %= MOD;
        }
        for (std::size_t i = 0; i != X.size(); ++i)
            X[i] = v[i] % MOD;
    }
    void INTT(poly &X)
    {
        NTT(X);
        std::reverse(X.begin() + 1, X.end());
        mint inv = mint(X.size()).inv();
        for (auto &i : X)
            i *= inv;
    }
    std::size_t up(std::size_t len) { return len == 1 ? 1 : 1 << (32 - __builtin_clz(len - 1)); }
    poly operator*(const poly &A, const poly &B)
    {
        std::size_t len = up(A.size() + B.size() - 1);
        poly a(A), b(B);
        a.resize(len);
        b.resize(len);
        NTT(a);
        NTT(b);
        for (std::size_t i = 0; i != len; ++i)
            a[i] *= b[i];
        INTT(a);
        a.resize(A.size() + B.size() - 1);
        return a;
    }
    poly operator*(const mint &A, const poly &B)
    {
        poly res = B;
        for (auto &i : res)
            i *= A;
        return res;
    }
    poly operator+(const poly &A, const poly &B)
    {
        poly res(std::max(A.size(), B.size()));
        for (std::size_t i = 0; i != A.size(); ++i)
            res[i] += A[i];
        for (std::size_t i = 0; i != B.size(); ++i)
            res[i] += B[i];
        return res;
    }
    poly operator-(const poly &A, const poly &B)
    {
        poly res(std::max(A.size(), B.size()));
        for (std::size_t i = 0; i != A.size(); ++i)
            res[i] += A[i];
        for (std::size_t i = 0; i != B.size(); ++i)
            res[i] -= B[i];
        return res;
    }
    poly INV(const poly &X)
    {
        assert(X.front());
        poly res(1, X.front().inv());
        for (std::size_t i = 1; i < X.size(); res.resize(i <<= 1))
        {
            poly tmp(X.begin(), X.begin() + std::min(X.size(), i << 1));
            tmp.resize(i << 2);
            res.resize(i << 2);
            NTT(tmp);
            NTT(res);
            for (std::size_t j = 0; j != i << 2; ++j)
                res[j] = (2 - res[j] * tmp[j]) * res[j];
            INTT(res);
        }
        res.resize(X.size());
        return res;
    }
    poly QIUDAO(const poly &X)
    {
        poly res = X;
        for (std::size_t i = 0; i != res.size(); ++i)
            res[i] *= i;
        return res;
    }
    poly JIFEN(const poly &X)
    {
        poly res = X;
        for (std::size_t i = 0; i != res.size(); ++i)
            res[i] *= inv[i];
        return res;
    }
    poly LN(const poly &X)
    {
        assert(X.front() == 1);
        poly res = QIUDAO(X) * INV(X);
        res.resize(X.size());
        return JIFEN(res);
    }
    poly resize(poly X, const std::size_t size) { return X.resize(size), X; }
    poly EXP(const poly &X)
    {
        assert(X.front() == 0);
        poly res(1, 1);
        for (std::size_t i = 1; i < X.size(); res.resize(i <<= 1))
            res = res * (poly{1} - LN(resize(res, std::min(X.size(), i << 1))) +
                         poly(X.begin(), X.begin() + std::min(X.size(), i << 1)));
        res.resize(X.size());
        return res;
    }
    poly v0, v, tmp, ans, H;
    poly solve1(int l, int r)
    {
        if (r - l == 1)
            return {h[l]};
        int mid = (l + r) >> 1;
        poly L(mid - l + 1), R(r - mid + 1);
        for (int i = 0; i <= mid - l; ++i)
            L[i] = ((mid - l - i) & 1 ? MOD - 1 : 1) * C(mid - l, i);
        for (int i = 0; i <= r - mid; ++i)
            R[i] = C(r - mid, i);
        L = L * solve1(mid, r);
        R = R * solve1(l, mid);
        return L + R;
    }
    std::pair<poly, poly> solve2(const poly &X, int l, int r)
    {
        if (r - l == 1)
            return {{X[l]}, {1, MOD - 2 * l}};
        int mid = (l + r) >> 1;
        std::pair<poly, poly> L = solve2(X, l, mid), R = solve2(X, mid, r);
        return {L.first * R.second + L.second * R.first, L.second * R.second};
    }
    poly Ln(poly G)
    {
        poly F;
        F.push_back(0);
        for (std::size_t i = 1; i != G.size(); ++i)
        {
            mint tmp = i * G[i];
            for (std::size_t j = 1; j != i; ++j)
                tmp -= (i - j) * F[i - j] * G[j];
            F.push_back(tmp / i);
        }
        return F;
    }
    poly Exp(poly F)
    {
        poly G;
        G.push_back(1);
        for (std::size_t i = 1; i != F.size(); ++i)
        {
            mint tmp = 0;
            for (std::size_t j = 0; j != i; ++j)
                tmp += (i - j) * F[i - j] * G[j];
            G.push_back(tmp / i);
        }
        return G;
    }
    signed main()
    {
        std::ios::sync_with_stdio(false);
        std::cin >> n;
        v.resize(n);
        init();
        for (int i = 0; i != n; ++i)
            std::cin >> v[i];
        v = EXP(v);
        for (int i = 0; i != n; ++i)
            std::cout << v[i] << " \n"[i + 1 == n];
        return 0;
    }
}

线性代数(结式、矩阵加法、减法、乘法、转上三角矩阵、行列式、转上海森堡矩阵、求上海森堡矩阵的行列式、解线性方程组、求特征多项式)

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
// #define debug
struct gg
{
    gg()
    {
        freopen("tree.in", "r", stdin) && freopen("tree.out", "w", stdout);
        std::ios::sync_with_stdio(false);
    }
} goodhabits;
int read()
{
    static int x;
    std::cin >> x;
    return x;
}
const int MOD = 998244353;
struct mint
{
    unsigned v;
    mint(unsigned v_ = 0) : v(v_) {}
    mint operator-() const { return v ? mint(MOD - v) : mint(); }
    mint &operator+=(const mint &X) { return (v += X.v) >= MOD ? v -= MOD : v, *this; }
    mint &operator-=(const mint &X) { return (v += MOD - X.v) >= MOD ? v -= MOD : v, *this; }
    mint &operator*=(const mint &X) { return v = 1ll * v * X.v % MOD, *this; }
    mint &operator/=(const mint &X) { return *this *= X.inv(); }
    mint pow(unsigned b) const
    {
        mint res(1), a = *this;
        while (b)
        {
            if (b & 1)
                res *= a;
            a *= a;
            b >>= 1;
        }
        return res;
    }
    mint inv() const { return pow(MOD - 2); }
    friend mint operator+(const mint &A, const mint &B) { return mint(A) += B; }
    friend mint operator-(const mint &A, const mint &B) { return mint(A) -= B; }
    friend mint operator*(const mint &A, const mint &B) { return mint(A) *= B; }
    friend mint operator/(const mint &A, const mint &B) { return mint(A) /= B; }
    friend std::istream &operator>>(std::istream &A, mint &B) { return A >> B.v; }
    friend std::ostream &operator<<(std::ostream &A, const mint &B) { return A << B.v; }
    friend bool operator==(const mint &A, const mint &B) { return A.v == B.v; }
    friend bool operator!=(const mint &A, const mint &B) { return A.v != B.v; }
    explicit operator bool() const { return v; }
};
typedef std::vector<mint> poly;
typedef std::valarray<mint> vector;
std::ostream &operator<<(std::ostream &A, const poly &B)
{
    for (auto i : B)
        A << std::setw(10) << i;
    return A;
}
std::ostream &operator<<(std::ostream &A, const vector &B)
{
    for (auto i : B)
        A << std::setw(10) << i;
    return A;
}
poly &operator*=(poly &A, const mint &B)
{
    for (auto &i : A)
        i *= B;
    return A;
}
mint res(poly A, poly B)
{
    mint r = 1;
    int n = A.size() - 1, m = B.size() - 1;
    r *= B.back().pow(n);
    B *= B.back().inv();
    while (B.size() > 1)
    {
        for (int i = n - m; i >= 0; --i)
        {
            mint g = A[i + m];
            for (int j = 0; j <= m; ++j)
                A[i + j] -= B[j] * g;
        }
        while (n && A[n] == 0)
            --n;
        if (A[n] == 0)
            return 0;
        A.resize(n + 1);
        std::swap(A, B);
        std::swap(n, m);
        if (n * m % 2)
            r *= MOD - 1;
        r *= B.back().pow(n);
        B *= B.back().inv();
    }
    return r;
}
struct matrix
{
    int d;
    std::valarray<vector> v;
    explicit matrix(int d_) : d(d_), v(vector(d), d) {}
    vector &operator[](const int &x) { return v[x]; }
    const vector &operator[](const int &x) const { return v[x]; }
    matrix &operator+=(const matrix &X) { return v += X.v, *this; }
    matrix &operator-=(const matrix &X) { return v -= X.v, *this; }
    matrix &operator*=(const matrix &X) { return *this = *this * X; }
    matrix &operator*=(const mint &X)
    {
        for (auto &i : v)
            i *= X;
        return *this;
    }
    matrix operator-() const
    {
        matrix ret = *this;
        for (auto &i : ret.v)
            i = -i;
        return ret;
    }
    friend matrix operator*(const matrix &A, const matrix &B)
    {
        int d = A.d;
        matrix res(d);
        for (int i = 0; i != d; ++i)
            for (int j = 0; j != d; ++j)
                for (int k = 0; k != d; ++k)
                    res[i][k] += A[i][j] * B[j][k];
        return res;
    }
    void Gauss()
    {
        for (int i = 0; i != d; ++i)
        {
            if (!v[i][i])
                for (int j = i; ++j != d;)
                    if (v[j][i])
                    {
                        v[i] += v[j];
                        break;
                    }
            mint g = v[i][i].inv();
            for (int j = i; ++j != d;)
                v[j] -= v[j][i] * g * v[i];
        }
    }
    mint Del() const
    {
        matrix tmp = *this;
        mint res = 1;
        tmp.Gauss();
        for (int i = 0; i != d; ++i)
            res *= tmp[i][i];
        return res;
    }
    mint DelHessenberg() const
    {
        mint f[d + 1];
        f[0] = 1;
        for (int i = 0; i != d; ++i)
        {
            mint t = 1;
            for (int j = 0; ++j; t *= -v[i + j][i + j - 1])
            {
                f[i + j] += f[i] * t * v[i][i + j - 1];
                if (i + j == d)
                    break;
            }
        }
        return f[d];
    }
    void Hessenberg()
    {
        for (int i = 0; i != d - 1; ++i)
        {
            if (!v[i + 1][i])
                for (int j = i + 1; ++j != d;)
                    if (v[j][i])
                    {
                        v[i + 1] += v[j];
                        for (int k = 0; k != d; ++k)
                            v[k][i + 1] -= v[k][j];
                        break;
                    }
            for (int j = d; --j != i + 1;)
            {
                mint tmp = v[j][i] / v[j - 1][i];
                v[j] -= tmp * v[j - 1];
                for (int k = 0; k != d; ++k)
                    v[k][j - 1] += tmp * v[k][j];
            }
        }
    }
    void solveEquation(vector &c)
    {
        for (int i = 0; i != d; ++i)
        {
            if (!v[i][i])
                for (int j = i; ++j != d;)
                    if (v[j][i])
                    {
                        v[i] += v[j];
                        break;
                    }
            mint g = v[i][i].inv();
            for (int j = i; ++j != d;)
                c[j] -= v[j][i] * g * c[i], v[j] -= v[j][i] * g * v[i];
        }
        for (int i = d; i--;)
        {
            for (int j = i; ++j != d;)
                c[i] -= v[i][j] * c[j];
            c[i] /= v[i][i];
        }
    }
};
struct work
{
    int n;
    matrix G;
    vector x;
    poly charp;
    work() : n(read()), G(n), x(n), charp() {}
    void solve()
    {
        for (int i = 0; i != n; ++i)
            for (int j = 0; j != n; ++j)
            {
                static mint tmp;
                std::cin >> tmp;
                G[i][j] -= tmp;
                G[j][j] += tmp;
            }
        matrix tmp = G;
        tmp.Gauss();
        for (int i = n; i--;)
        {
            mint y = 0;
            for (int j = i; ++j != n;)
                y -= x[j] * tmp[i][j];
            x[i] = tmp[i][i] ? y / tmp[i][i] : 1;
        }
        tmp = G;
        for (int i = 0; i != n; ++i)
            if (x[i])
            {
                tmp[i].resize(n);
                tmp[i][i] = 1;
                x *= tmp.Del() / x[i];
                break;
            }
        tmp = -G;
        tmp.Hessenberg();
        vector R(n);
        matrix L(n);
        for (int i = 0; i != n; ++i)
        {
            L[i][0] = 1;
            for (int j = 1; j != n; ++j)
                L[i][j] = L[i][j - 1] * i;
            R[i] = tmp.DelHessenberg() - mint(i).pow(n);
            for (int j = 0; j != n; ++j)
                tmp[j][j] += 1;
        }
        L.solveEquation(R);
        charp.assign(std::begin(R), std::end(R));
        charp.push_back(1);
    }
} A, B;
signed main()
{
    A.solve();
    B.solve();
    poly p(++A.charp.begin(), A.charp.end()), q(++B.charp.begin(), B.charp.end());
    for (std::size_t i = 1; i < q.size(); i += 2)
        q[i] *= MOD - 1;
    mint g = res(p, q);
    for (int i = 0; i != A.n; ++i)
        for (int j = 0; j != B.n; ++j)
            std::cout << A.x[i] * B.x[j] * g << " \n"[j + 1 == B.n];
    return 0;
}

BM

CPP
using poly = std::vector<mint>;
poly BM(const poly &x)
{
    poly cur(1), lst(1);
    cur[0] = lst[0] = 1;
    int lp = 0;
    mint lt = 0;
    for (int i = 0; i < (int)x.size(); ++i)
    {
        mint t = 0;
        for (int j = 0; j < (int)cur.size(); ++j)
        {
            t += x[i - j] * cur[j];
        }
        if (t == 0)
            continue;
        if ((int)cur.size() == 1)
        {
            cur.resize(i + 2);
            lp = i, lt = t;
            continue;
        }
        mint tmp = -t / lt;
        poly c(i - lp);
        for (mint v : lst)
            c.push_back(tmp * v);
        if (c.size() < cur.size())
            c.resize(cur.size());
        else
            lst = cur, lp = i, lt = t;
        for (int j = 0; j < (int)cur.size(); ++j)
            c[j] += cur[j];
        cur = c;
    }
    std::reverse(G.begin(), G.end());
    return cur;
}
poly mul(const poly &A, const poly &B, const poly &C)
{
    poly res(A.size() + B.size() - 1);
    for (std::size_t i = 0; i != A.size(); ++i)
        for (std::size_t j = 0; j != B.size(); ++j)
            res[i + j] += A[i] * B[j];
    while (res.size() >= C.size())
    {
        mint v = res.back() / C.back();
        for (std::size_t i = 1; i <= C.size(); ++i)
            res.end()[-i] -= v * C.end()[-i];
        res.pop_back();
    }
    return res;
}
poly power(poly A, long long B, poly C)
{
    poly res = {1};
    while (B)
    {
        if (B & 1)
            res = mul(res, A, C);
        A = mul(A, A, C);
        B >>= 1;
    }
    return res;
}

动态 DP

CPP
#include <bits/stdc++.h>
using namespace std;
mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
#define rep(i, a, b) for (int i = (a), I = (b); i <= I; ++i)
#define per(i, a, b) for (int i = (a), I = (b); i >= I; --i)
using i64 = long long;
using pii = pair<int, int>;
template<typename T> void up(T &x, T y) { if (x < y) x = y; }
template<typename T> void down(T &x, T y) { if (x > y) x = y; }

const int N = 1000005, inf = 1e9;
int n, m, a[N], fa[N], dep[N], siz[N], son[N], top[N];
vector<int> e[N];
int dp[N][2], f[N][2];

void dfs1(int u) {
    siz[u] = 1;
    dp[u][1] = a[u];
    for (auto v : e[u]) {
        e[v].erase(find(e[v].begin(), e[v].end(), u));
        fa[v] =  u, dep[v] = dep[u] + 1;
        dfs1(v);
        siz[u] += siz[v];
        if (siz[v] > siz[son[u]]) son[u] = v;
        dp[u][0] += max(dp[v][0], dp[v][1]);
        dp[u][1] += dp[v][0];
    }
    f[u][0] = dp[u][0], f[u][1] = dp[u][1];
    if (son[u]) {
        f[u][0] -= max(dp[son[u]][0], dp[son[u]][1]);
        f[u][1] -= dp[son[u]][0];
    }
}

using mat = array<array<int, 2>, 2>;
mat operator*(const mat &lhs, const mat &rhs) {
    mat res;
    rep(i, 0, 1) rep(j, 0, 1) res[i][j] = max(lhs[i][0] + rhs[0][j], lhs[i][1] + rhs[1][j]);
    return res;
}
mat get_mat(int u) {
    return {f[u][0], f[u][1], f[u][0], -inf};
}

const int M = N << 1;
int rt[N], ls[M], rs[M], md[M], par[M], tot;
pii tmp[N];
mat val[M];

void push_up(int p) {
    val[p] = val[rs[p]] * val[ls[p]];
}
int build(int l, int r) { 
    if (l == r) {
        int u = tmp[l].first;
        val[u] = get_mat(u);
        return u;
    }   
    int p = ++tot;
    int mid = l, sum = 0, cur = tmp[l].second;
    rep(i, l, r) sum += tmp[i].second;
    while (mid + 1 < r && (cur + tmp[mid + 1].second) * 2 <= sum) cur += tmp[++mid].second;
    md[p] = mid;
    ls[p] = build(l, mid);
    rs[p] = build(mid + 1, r);
    par[ls[p]] = par[rs[p]] = p;
    push_up(p);
    return p;
}
void dfs2(int u) {
    for (int x = u; x; x = son[x]) for (auto y : e[x]) if (y != son[x]) dfs2(y);
    int cnt = 0;
    for (int x = u; x; x = son[x]) tmp[++cnt] = {x, siz[x] - siz[son[x]]}, top[x] = u;
    rt[u] = build(1, cnt);
}
void modify(int u) {
    val[u] = get_mat(u);
    for (u = par[u]; u; u = par[u]) push_up(u);
}

void query_sub(int u) {
    int r = rt[u];
    dp[u][0] = val[r][0][0], dp[u][1] = val[r][0][1];
}
void modify(int u, int x) {
    f[u][1] += x - a[u];
    a[u] = x;
    while (u) {
        int t = top[u], x = fa[t];
        f[x][0] -= max(dp[t][0], dp[t][1]);
        f[x][1] -= dp[t][0];
        modify(u);
        query_sub(t);
        f[x][0] += max(dp[t][0], dp[t][1]);
        f[x][1] += dp[t][0];
        u = x;
    }
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);

    cin >> n >> m;
    rep(i, 1, n) cin >> a[i];
    rep(i, 1, n - 1) {
        int u, v; 
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    
    dfs1(1), tot = n, dfs2(1);

    int last_ans = 0;
    while (m--) {
        int u, x; 
        cin >> u >> x;
        u ^= last_ans;
        modify(u, x);
        cout << (last_ans = max(dp[1][0], dp[1][1])) << "\n";
    }

    return 0;
}

最大网络流

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
int n, m, s, t, head[5005], cur[5005], cnt;
long long flow, dis[5005];
struct edge
{
    int n, t;
    long long v;
} e[100005];
void add_edge(int A, int B, long long C)
{
    e[cnt].n = head[A];
    e[cnt].t = B;
    e[cnt].v = C;
    head[A] = cnt++;
}
void add_flow(int A, int B, long long C)
{
    add_edge(A, B, C);
    add_edge(B, A, 0);
}
bool get_dis()
{
    std::fill(dis, dis + n, -1);
    dis[s] = 0;
    std::queue<int> que;
    que.push(s);
    while (!que.empty())
    {
        int now = que.front();
        que.pop();
        for (int i = head[now]; ~i; i = e[i].n)
            if (e[i].v && !~dis[e[i].t])
            {
                dis[e[i].t] = dis[now] + 1;
                que.push(e[i].t);
            }
    }
    return ~dis[t];
}
long long dfs(int now = s, long long flow = LLONG_MAX)
{
    if (now == t || !flow)
        return flow;
    long long res = 0;
    for (int &i = cur[now]; ~i; i = e[i].n)
        if (e[i].v && dis[e[i].t] == dis[now] + 1)
        {
            int tmp = dfs(e[i].t, std::min(flow, e[i].v));
            e[i].v -= tmp;
            e[i ^ 1].v += tmp;
            res += tmp;
            flow -= tmp;
            if (!flow)
                break;
        }
    return res;
}
void Dinic()
{
    while (get_dis())
    {
        std::copy(head, head + n, cur);
        flow += dfs();
    }
}
signed main()
{
    std::ios::sync_with_stdio(false);
    std::memset(head, -1, sizeof(head));
    std::cin >> n >> m >> s >> t;
    ++n;
    for (int i = 0, u, v, w; i != m; ++i)
    {
        std::cin >> u >> v >> w;
        add_flow(u, v, w);
    }
    Dinic();
    std::cout << flow << std::endl;
    return 0;
}

最小费用最大流

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
int n, m, s, t, head[5005], cur[5005], cnt, flow;
long long cost, dis[5005], h[5005];
bool in[5005];
struct edge
{
    int n, t, v, w;
} e[100005];
void add_edge(int A, int B, int C, int D)
{
    e[cnt].n = head[A];
    e[cnt].t = B;
    e[cnt].v = C;
    e[cnt].w = D;
    head[A] = cnt++;
}
void add_flow(int A, int B, int C, int D)
{
    add_edge(A, B, C, D);
    add_edge(B, A, 0, -D);
}
bool get_dis()
{
    for (int i = 0; i <= n; ++i)
        h[i] += dis[i];
    std::fill(dis, dis + n, LLONG_MAX);
    dis[s] = 0;
    static bool flag;
    if (!flag)
    {
        std::queue<int> que;
        que.push(s);
        in[s] = true;
        while (!que.empty())
        {
            int now = que.front();
            que.pop();
            in[now] = false;
            for (int i = head[now]; ~i; i = e[i].n)
            {
                if (e[i].v && dis[e[i].t] > dis[now] + e[i].w)
                {
                    dis[e[i].t] = dis[now] + e[i].w;
                    if (!in[e[i].t])
                        que.push(e[i].t);
                    in[e[i].t] = true;
                }
            }
        }
        flag = true;
    }
    else
    {
        std::priority_queue<std::pair<long long, int>> que;
        que.push({-dis[s], s});
        while (!que.empty())
        {
            int now = que.top().second;
            if (dis[now] + que.top().first)
            {
                que.pop();
                continue;
            }
            que.pop();
            for (int i = head[now]; ~i; i = e[i].n)
                if (e[i].v && dis[e[i].t] > dis[now] + e[i].w + h[now] - h[e[i].t])
                    que.push({-(dis[e[i].t] = dis[now] + e[i].w + h[now] - h[e[i].t]), e[i].t});
        }
    }
    return dis[t] != LLONG_MAX;
}
int dfs(int now = s, int flow = INT_MAX)
{
    if (now == t || !flow)
        return flow;
    in[now] = true;
    int res = 0;
    for (int &i = cur[now]; ~i; i = e[i].n)
        if (e[i].v && !in[e[i].t] && dis[e[i].t] + h[e[i].t] == dis[now] + h[now] + e[i].w)
        {
            int tmp = dfs(e[i].t, std::min(flow, e[i].v));
            cost += 1ll * e[i].w * tmp;
            e[i].v -= tmp;
            e[i ^ 1].v += tmp;
            res += tmp;
            flow -= tmp;
            if (!flow)
                break;
        }
    in[now] = false;
    return res;
}
void Dinic()
{
    while (get_dis())
    {
        std::copy(head, head + n, cur);
        flow += dfs();
    }
}
signed main()
{
    std::ios::sync_with_stdio(false);
    std::memset(head, -1, sizeof(head));
    std::cin >> n >> m >> s >> t;
    ++n;
    for (int i = 0, u, v, w, c; i != m; ++i)
    {
        std::cin >> u >> v >> w >> c;
        add_flow(u, v, w, c);
    }
    Dinic();
    std::cout << flow << ' ' << cost << std::endl;
    return 0;
}

二分图最大匹配

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
std::vector<int> to[505];
int n, m, k, match[505], ans, vis[505];
bool dfs(const int &now, const int &tag)
{
    if (vis[now] == tag)
        return false;
    vis[now] = tag;
    for (auto i : to[now])
        if (!match[i] || dfs(match[i], tag))
        {
            match[i] = now;
            return true;
        }
    return false;
}
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin >> n >> m >> k;
    for (int i = 1, u, v; i <= k; ++i)
    {
        std::cin >> u >> v;
        to[u].push_back(v);
    }
    for (int i = 1; i <= n; ++i)
        if (dfs(i, i))
            ++ans;
    std::cout << ans << std::endl;
    return 0;
}

二分图最大权完美匹配

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
int n, m, lst[505], matchl[505], matchr[505];
long long v[505][505], lm[505], rm[505], d[505];
bool visl[505], visr[505];
void Match(int now)
{
    static int tmp;
    while (now)
    {
        tmp = matchl[lst[now]];
        matchl[lst[now]] = now;
        matchr[now] = lst[now];
        now = tmp;
    }
}
void bfs(int s)
{
    std::fill(visl + 1, visl + 1 + n, false);
    std::fill(visr + 1, visr + 1 + n, false);
    std::fill(d + 1, d + 1 + n, LLONG_MAX / 4);
    std::queue<int> que;
    que.push(s);
    while (true)
    {
        while (!que.empty())
        {
            int now = que.front();
            que.pop();
            visl[now] = true;
            for (int i = 1; i <= n; ++i)
                if (!visr[i] && lm[now] + rm[i] - v[now][i] < d[i])
                {
                    d[i] = lm[now] + rm[i] - v[now][i];
                    lst[i] = now;
                    if (!d[i])
                    {
                        visr[i] = true;
                        if (!matchr[i])
                            return Match(i);
                        else
                            que.push(matchr[i]);
                    }
                }
        }
        long long down = LLONG_MAX / 4;
        for (int i = 1; i <= n; ++i)
            if (!visr[i])
                down = std::min(down, d[i]);
        for (int i = 1; i <= n; ++i)
        {
            if (visl[i])
                lm[i] -= down;
            if (visr[i])
                rm[i] += down;
            else
                d[i] -= down;
        }
        for (int i = 1; i <= n; ++i)
            if (!visr[i] && !d[i])
            {
                visr[i] = true;
                if (!matchr[i])
                    return Match(i);
                else
                    que.push(matchr[i]);
            }
    }
}
long long KM()
{
    for (int i = 1; i <= n; ++i)
        lm[i] = *std::max_element(v[i] + 1, v[i] + 1 + n);
    for (int i = 1; i <= n; ++i)
        bfs(i);
    long long res = 0;
    for (int i = 1; i <= n; ++i)
        res += lm[i] + rm[i];
    return res;
}
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            v[i][j] = LLONG_MIN / 4;
    for (int i = 1; i <= m; ++i)
    {
        static int a, b;
        static long long c;
        std::cin >> a >> b >> c;
        v[a][b] = std::max(v[a][b], c);
    }
    std::cout << KM() << std::endl;
    for (int i = 1; i <= n; ++i)
        std::cout << matchr[i] << " \n"[i == n];
    return 0;
}

左偏树

CPP
class node
{
public:
    int v, p;
    friend bool operator<(const node &A, const node &B)
    {
        return A.v == B.v ? A.p < B.p : A.v < B.v;
    }
};
template <class Type>
class heap
{
private:
    class node
    {
    private:
        int dis;
        void swap_son() { swap(lson, rson); }
        bool bad() const { return lson_dis() < rson_dis(); }
        int lson_dis() const { return lson ? lson->dis : -1; }
        int rson_dis() const { return rson ? rson->dis : -1; }

    public:
        node(Type VAL = Type(), node *LSON = 0, node *RSON = 0) : dis(0), val(VAL), lson(LSON), rson(RSON) {}
        Type val;
        node *lson, *rson;
        void update()
        {
            if (bad())
                swap_son();
            dis = rson_dis() + 1;
        }
        friend node *merge_node(node *A, node *B)
        {
            if (A == nullptr)
                return B;
            if (B == nullptr)
                return A;
            if (B->val < A->val)
                swap(A, B);
            A->rson = merge_node(A->rson, B);
            A->update();
            return A;
        }
    };
    node *root;

public:
    bool empty() const { return root == 0; }
    Type top() const { return empty() ? Type() : root->val; }
    void push(const Type &x)
    {
        if (empty())
            root = new node(x);
        else
            merge_node(root, new node(x));
    }
    void pop()
    {
        if (empty())
            return;
        node *tmp = root;
        root->update();
        if (root->rson)
            root = merge_node(root->lson, root->rson);
        else if (root->lson)
            root = root->lson;
        else
            root = 0;
        delete tmp;
    }
    void merge(heap &x)
    {
        if (x.empty() || &x == this)
            return;
        if (empty())
        {
            root = x.root;
            return;
        }
        root = merge_node(root, x.root);
        x.root = 0;
    }
};

平衡树

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
unsigned long long seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937 Rand(seed);
struct treap
{
    struct node
    {
        node *lson, *rson;
        int siz, v, w;
        node(int x) : lson(), rson(), siz(1), v(x), w(Rand()) {}
        void pushup() { siz = (lson ? lson->siz : 0) + 1 + (rson ? rson->siz : 0); }
    } * root;
    void insert(int x)
    {
        if (root == nullptr)
            return void(root = new node(x));
        std::pair<node *, node *> tmp = split(root, x);
        root = merge(merge(tmp.first, new node(x)), tmp.second);
    }
    void erase(int x)
    {
        std::pair<node *, node *> tmp = split(root, x), g = split(tmp.second, x + 1);
        root = merge(tmp.first, merge(merge(g.first->lson, g.first->rson), g.second));
        delete g.first;
    }
    int rk(int x) const { return rk_(root, x); }
    int rt(int x) const { return rt_(root, x); }
    int rk_(node *now, int x) const
    {
        if (now == nullptr)
            return 0;
        if (now->v < x)
            return (now->lson ? now->lson->siz : 0) + 1 + rk_(now->rson, x);
        else
            return rk_(now->lson, x);
    }
    int rt_(node *now, int x) const
    {
        if (now->lson)
        {
            if (x < now->lson->siz)
                return rt_(now->lson, x);
            x -= now->lson->siz;
        }
        if (x == 0)
            return now->v;
        --x;
        return rt_(now->rson, x);
    }
    std::pair<node *, node *> split(node *now, int x)
    {
        if (now == nullptr)
            return {};
        std::pair<node *, node *> tmp;
        if (now->v < x)
        {
            tmp = split(now->rson, x);
            now->rson = tmp.first;
            tmp.first = now;
        }
        else
        {
            tmp = split(now->lson, x);
            now->lson = tmp.second;
            tmp.second = now;
        }
        now->pushup();
        return tmp;
    }
    node *merge(node *A, node *B)
    {
        if (A == nullptr)
            return B;
        if (B == nullptr)
            return A;
        if (A->w < B->w)
        {
            A->rson = merge(A->rson, B);
            A->pushup();
            return A;
        }
        else
        {
            B->lson = merge(A, B->lson);
            B->pushup();
            return B;
        }
    }
} t;
int n, m;
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin >> n >> m;
    for (int i = 1, x; i <= n; ++i)
    {
        std::cin >> x;
        t.insert(x);
    }
    int ans = 0;
    for (int i = 1, lst = 0, opt, x; i <= m; ++i)
    {
        std::cin >> opt >> x;
        x ^= lst;
        switch (opt)
        {
        case 1:
            t.insert(x);
            break;
        case 2:
            t.erase(x);
            break;
        case 3:
            ans ^= (lst = t.rk(x) + 1);
            break;
        case 4:
            ans ^= (lst = t.rt(x - 1));
            break;
        case 5:
            ans ^= (lst = t.rt(t.rk(x) - 1));
            break;
        case 6:
            ans ^= (lst = t.rt(t.rk(x + 1)));
            break;
        }
        // if (opt > 2)
        //     std::cout << lst << '\n';
    }
    std::cout << ans << std::endl;
    return 0;
}

可持久化平衡树

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
// #define debug
unsigned long long seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937_64 Rand(seed);
struct node
{
    node *lson, *rson;
    int val;
    unsigned size : 19, w : 13;
    node(int v = 0) : lson(), rson(), val(v), size(1), w(Rand()) {}
    void pushup() { size = (lson ? lson->size : 0) + 1 + (rson ? rson->size : 0); }
};
class treap
{
    node *root;
    static unsigned get(node *now) { return now ? now->size : 0; }
    static node *merge(node *A, node *B)
    {
        if (!A)
            return B;
        if (!B)
            return A;
        if (A->w < B->w)
        {
            node *res = new node(*A);
            res->rson = merge(A->rson, B);
            res->pushup();
            return res;
        }
        else
        {
            node *res = new node(*B);
            res->lson = merge(A, B->lson);
            res->pushup();
            return res;
        }
    }
    static std::pair<node *, node *> split(node *X, int val)
    {
        if (!X)
            return {};
        if (X->val < val)
        {
            node *res = new node(*X);
            std::pair<node *, node *> tmp = split(X->rson, val);
            res->rson = tmp.first;
            tmp.first = res;
            res->pushup();
            return tmp;
        }
        else
        {
            node *res = new node(*X);
            std::pair<node *, node *> tmp = split(X->lson, val);
            res->lson = tmp.second;
            tmp.second = res;
            res->pushup();
            return tmp;
        }
    }
    static unsigned rk_(node *now, int val)
    {
        if (!now)
            return 0;
        if (val <= now->val)
            return rk_(now->lson, val);
        else
            return get(now->lson) + 1 + rk_(now->rson, val);
    }
    static int find_(node *now, unsigned val)
    {
        if (val < get(now->lson))
            return find_(now->lson, val);
        val -= get(now->lson);
        if (val == 0)
            return now->val;
        --val;
        return find_(now->rson, val);
    }

public:
    treap(node *root = nullptr) : root(root) {}
    treap insert(int val) const
    {
        std::pair<node *, node *> tmp = split(root, val);
        return merge(tmp.first, merge(new node(val), tmp.second));
    }
    treap erase(int val) const
    {
        std::pair<node *, node *> A = split(root, val);
        std::pair<node *, node *> B = split(A.second, val + 1);
        if (B.first)
            return merge(merge(A.first, B.first->lson), merge(B.first->rson, B.second));
        else
            return merge(A.first, B.second);
    }
    unsigned rk(int val) const { return rk_(root, val); }
    int find(unsigned val) const { return find_(root, val); }
    void print(node *now) const
    {
        if (!root)
            return;
        if (!now)
            now = root, std::cout << 0 << ' ' << now << ',' << now->val << std::endl;
        if (now->lson)
            std::cout << now << ',' << now->val << ' ' << now->lson << ',' << now->lson->val << ' ' << 0 << std::endl,
                print(now->lson);
        if (now->rson)
            std::cout << now << ',' << now->val << ' ' << now->rson << ',' << now->rson->val << ' ' << 1 << std::endl,
                print(now->rson);
    }
} t[500005];
int n;
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    t[0] = t[0].insert(-INT_MAX);
    t[0] = t[0].insert(+INT_MAX);
    std::cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        static int v, opt, x;
        std::cin >> v >> opt >> x;
        t[i] = t[v];
        switch (opt)
        {
        case 1:
            t[i] = t[i].insert(x);
            break;
        case 2:
            t[i] = t[i].erase(x);
            break;
        case 3:
            std::cout << t[i].rk(x) << '\n';
            break;
        case 4:
            std::cout << t[i].find(x) << '\n';
            break;
        case 5:
            std::cout << t[i].find(t[i].rk(x) - 1) << '\n';
            break;
        case 6:
            std::cout << t[i].find(t[i].rk(x + 1)) << '\n';
            break;
        }
    }
    return 0;
}

文艺平衡树

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
// #define debug
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937 Rand(seed);
int n, m;
class treap
{
    struct node
    {
        node *lson, *rson;
        int v;
        unsigned w;
        std::size_t size;
        bool rev;
        node(int v_) : lson(), rson(), v(v_), w(Rand()), size(1), rev(false) {}
#define size(x) ((x) ? (x)->size : 0)
        void pushup()
        {
            size = 1 + size(lson) + size(rson);
        }
        void pushdown()
        {
            if (rev)
            {
                std::swap(lson, rson);
                if (lson)
                    lson->rev ^= true;
                if (rson)
                    rson->rev ^= true;
                rev = false;
            }
        }
    };
    node *root;
    node *merge(node *A, node *B)
    {
        if (!A)
            return B;
        if (!B)
            return A;
        if (A->w < B->w)
        {
            A->pushdown();
            A->rson = merge(A->rson, B);
            A->pushup();
            return A;
        }
        else
        {
            B->pushdown();
            B->lson = merge(A, B->lson);
            B->pushup();
            return B;
        }
    }
    std::pair<node *, node *> split(node *X, std::size_t size)
    {
        std::pair<node *, node *> res;
        if (!X)
            return res;
        X->pushdown();
        if (size(X->lson) < size)
        {
            std::pair<node *, node *> tmp = split(X->rson, size - size(X->lson) - 1);
            X->rson = tmp.first;
            res.first = X;
            res.second = tmp.second;
        }
        else
        {
            std::pair<node *, node *> tmp = split(X->lson, size);
            X->lson = tmp.second;
            res.first = tmp.first;
            res.second = X;
        }
        X->pushup();
        return res;
    }
    void visit_(node *now)
    {
        if (!now)
            return;
        now->pushdown();
        visit_(now->lson);
        std::cout << now->v << ' ';
        visit_(now->rson);
    }

public:
    void push_back(int v) { root = merge(root, new node(v)); }
    void reverse(std::size_t l, std::size_t r)
    {
        std::pair<node *, node *> tmp = split(root, l);
        node *L = tmp.first;
        tmp = split(tmp.second, r - l);
        tmp.first->rev ^= true;
        root = merge(L, merge(tmp.first, tmp.second));
    }
    void visit()
    {
        visit_(root);
    }
} a;
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        a.push_back(i);
    for (int i = 1, x, y; i <= m; ++i)
    {
        std::cin >> x >> y;
        a.reverse(--x, y);
    }
    a.visit();
    std::cout << std::endl;
    return 0;
}

可持久化文艺平衡树

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
// #define debug
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937 Rand(seed);
struct __attribute__((packed)) node
{
    node *lson, *rson;
    int v : 21;
    long long sum : 39;
    unsigned w : 16, size : 18;
    bool rev : 1;
    node(int v_) : lson(), rson(), v(v_), sum(v_), w(Rand()), size(1), rev() {}
#define size(x) ((x) ? (x)->size : 0)
    void pushup()
    {
        size = 1 + size(lson) + size(rson);
        sum = v + (lson ? lson->sum : 0) + (rson ? rson->sum : 0);
    }
    void pushdown()
    {
        if (rev)
        {
            node *tmp = lson;
            lson = rson;
            rson = tmp;
            if (lson)
                (lson = new node(*lson))->rev ^= true;
            if (rson)
                (rson = new node(*rson))->rev ^= true;
            rev = false;
        }
    }
};
class treap
{
private:
    node *root;
    node *merge(node *A, node *B) const
    {
        if (!A)
            return B;
        if (!B)
            return A;
        node *res;
        if (A->w < B->w)
        {
            res = new node(*A);
            res->pushdown();
            res->rson = merge(res->rson, B);
            res->pushup();
        }
        else
        {
            res = new node(*B);
            res->pushdown();
            res->lson = merge(A, res->lson);
            res->pushup();
        }
        return res;
    }
    std::pair<node *, node *> split(node *X, unsigned cnt)
    {
        std::pair<node *, node *> res;
        if (!X)
            return res;
        X = new node(*X);
        X->pushdown();
        if (size(X->lson) < cnt)
        {
            res.first = X;
            std::pair<node *, node *> tmp = split(X->rson, cnt - 1 - size(X->lson));
            res.second = tmp.second;
            X->rson = tmp.first;
        }
        else
        {
            res.second = X;
            std::pair<node *, node *> tmp = split(X->lson, cnt);
            res.first = tmp.first;
            X->lson = tmp.second;
        }
        X->pushup();
        return res;
    }
    long long sum(node *now, unsigned cnt)
    {
        if (!now || !cnt)
            return 0;
        if (size(now) <= cnt)
            return now->sum;
        long long res = 0;
        now->pushdown();
        if (now->lson)
        {
            if (now->lson->size <= cnt)
                res += now->lson->sum, cnt -= now->lson->size;
            else
                return sum(now->lson, cnt);
        }
        if (cnt)
            return res + now->v + sum(now->rson, cnt - 1);
        return res;
    }

public:
    explicit treap(node *root_) : root(root_) {}
    treap insert(unsigned pos, int v)
    {
        std::pair<node *, node *> tmp = split(root, pos);
        return treap(merge(merge(tmp.first, new node(v)), tmp.second));
    }
    treap erase(unsigned pos)
    {
        std::pair<node *, node *> tmp = split(root, pos);
        return treap(merge(tmp.first, split(tmp.second, 1).second));
    }
    treap reverse(unsigned l, unsigned r)
    {
        std::pair<node *, node *> tmp = split(root, l);
        node *L = tmp.first;
        tmp = split(tmp.second, r - l);
        node *m = new node(*tmp.first);
        m->rev ^= true;
        return treap(merge(L, merge(m, tmp.second)));
    }
    long long query(unsigned l, unsigned r) { return sum(root, r) - sum(root, l); }
};
std::vector<treap> a;
int n;
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin >> n;
    a.push_back(treap(nullptr));
    for (int i = 1, v, opt; i <= n; ++i)
    {
        static long long p, x, ans;
        std::cin >> v >> opt;
        switch (opt)
        {
        case 1:
            std::cin >> p >> x;
            p ^= ans;
            x ^= ans;
            a.push_back(a[v].insert(p, x));
            break;
        case 2:
            std::cin >> p;
            p ^= ans;
            a.push_back(a[v].erase(p - 1));
            break;
        case 3:
            std::cin >> p >> x;
            p ^= ans;
            x ^= ans;
            a.push_back(a[v].reverse(--p, x));
            break;
        case 4:
            std::cin >> p >> x;
            p ^= ans;
            x ^= ans;
            a.push_back(a[v]);
            std::cout << (ans = a[i].query(--p, x)) << std::endl;
            break;
        }
    }
    return 0;
}

平面计算几何

CPP
// This Code was made by Chinese_zjc_.
#include <bits/stdc++.h>
const double eps = 1e-10;
const double PI = std::acos(-1);
template <class T>
auto sqr(T x) { return x * x; }
struct point
{
    double x, y;
    point() : x(), y() {}
    point(double x, double y) : x(x), y(y) {}
    point operator~() const { return point(-y, x); }
    point operator-() const { return point(-x, -y); }
    point &operator+=(const point &X) { return x += X.x, y += X.y, *this; }
    point &operator-=(const point &X) { return x -= X.x, y -= X.y, *this; }
    point &operator*=(const double &X) { return x *= X, y *= X, *this; }
    friend point operator+(const point &A, const point &B) { return point(A) += B; }
    friend point operator-(const point &A, const point &B) { return point(A) -= B; }
    friend point operator*(const point &A, const double &B) { return point(A) *= B; }
    friend point operator*(const double &A, const point &B) { return point(B) *= A; }
    friend double operator*(const point &A, const point &B) { return A.x * B.x + A.y * B.y; }
    friend double operator/(const point &A, const point &B) { return A.x * B.y - A.y * B.x; }
    friend std::istream &operator>>(std::istream &A, point &B) { return A >> B.x >> B.y; }
    friend std::ostream &operator<<(std::ostream &A, const point &B) { return A << B.x << ' ' << B.y; }
    friend bool operator<=(const point &A, const point &B) { return A.x <= B.x && A.y <= B.y; }
    friend point min(const point &A, const point &B) { return point(std::min(A.x, B.x), std::min(A.y, B.y)); }
    friend point max(const point &A, const point &B) { return point(std::max(A.x, B.x), std::max(A.y, B.y)); }
    double angle() const { return std::atan2(y, x); }
    double abs() const { return std::sqrt(sqr(*this)); }
};
struct line
{
    point A, B;
    line() : A(), B() {}
    line(point A, point B) : A(A), B(B) {}
    point vec() const { return B - A; }
    double angle() const { return vec().angle(); }
    friend std::istream &operator>>(std::istream &A, line &B) { return A >> B.A >> B.B; }
    friend std::ostream &operator<<(std::ostream &A, const line &B) { return A << B.A << ' ' << B.B; }
    friend bool operator<(const line &A, const line &B)
    {
        return (B.angle() - A.angle() ?: (B.B - A.A) / (A.B - B.A)) > 0;
    }
    friend bool operator==(const line &A, const line &B) { return (A.B - A.A) / (B.B - B.A) == 0; }
};
struct circle
{
    point O;
    double r;
    friend std::istream &operator>>(std::istream &A, circle &B) { return A >> B.O >> B.r; }
    friend std::ostream &operator<<(std::ostream &A, const circle &B) { return A << B.O << ' ' << B.r; }
};
struct polygon : std::vector<point>
{
    using std::vector<point>::vector;
};
point projection(line a, point X) // 点X投影至直线a
{
    a.B -= a.A;
    X -= a.A;
    return a.A + (a.B * X) / (a.B * a.B) * a.B;
}
point reflection(line a, point X) // 点X关于直线a对称点
{
    a.B -= a.A;
    X -= a.A;
    return a.A + 2 * (a.B * X) / (a.B * a.B) * a.B - X;
}
std::string clockwise(line a, point X) // 点X相对线a位置
{
    a.B -= a.A;
    X -= a.A;
    if (a.B / X > 0)
        return "COUNTER_CLOCKWISE";
    if (a.B / X < 0)
        return "CLOCKWISE";
    if (a.B * X < 0)
        return "ONLINE_BACK";
    if ((a.A - a.B) * (X - a.B) < 0)
        return "ONLINE_FRONT";
    return "ON_SEGMENT";
}
bool orthogonal(line a, line b) // 直线a与直线b是否正交
{
    return std::abs(a.vec() * b.vec()) < eps;
}
bool parallel(line a, line b) // 直线a与直线b是否平行
{
    return std::abs(a.vec() / b.vec()) < eps;
}
int sign(double x) { return x < 0 ? -1 : x > 0; }
bool intersection(line a, line b) // 线段a与线段b是否相交
{
    if (std::abs(sign((b.A - a.A) / (a.B - a.A)) + sign((b.B - a.A) / (a.B - a.A))) == 2)
        return false;
    if (std::abs(sign((a.A - b.A) / (b.B - b.A)) + sign((a.B - b.A) / (b.B - b.A))) == 2)
        return false;
    return max(min(a.A, a.B), min(b.A, b.B)) <= min(max(a.A, a.B), max(b.A, b.B));
}
point cross(line a, line b) // 直线a与直线b的交点
{
    a.B -= a.A;
    b.A -= a.A;
    b.B -= a.A;
    return a.A + ((b.B - b.A) / b.A) / ((b.B - b.A) / a.B) * a.B;
}
double distance(line a, point X) // 点X与线段a的距离的平方
{
    a.B -= a.A;
    X -= a.A;
    if (X * a.B < 0)
        return sqr(X);
    if ((a.B - X) * a.B < 0)
        return sqr(a.B - X);
    return sqr(a.B / X) / sqr(a.B);
}
double distance(line a, line b) // 线段AB与线段CD的距离的平方
{
    if (intersection(a, b))
        return 0;
    return std::min({distance(a, b.A), distance(a, b.B), distance(b, a.A), distance(b, a.B)});
}
double area(polygon P) // 多边形P的面积
{
    double res = 0;
    for (std::size_t i = 0; i != P.size(); ++i)
        res += P[i] / P[(i + 1) % P.size()];
    return res / 2;
}
bool isConvex(polygon P) // 多边形P是否是凸的
{
    for (std::size_t i = 0; i != P.size(); ++i)
        if ((P[i] - P[(i + 1) % P.size()]) / (P[(i + 1) % P.size()] - P[(i + 2) % P.size()]) < 0)
            return false;
    return true;
}
std::string inPolygon(polygon P, point X) // 点X是否在多边形P中
{
    bool in = false;
    for (auto &i : P)
        i -= X;
    for (std::size_t i = 0; i != P.size(); ++i)
    {
        point A = P[i], B = P[(i + 1) % P.size()];
        if (clockwise(line(A, B), point()) == "ON_SEGMENT")
            return "ON";
        if (A.x < B.x)
            std::swap(A, B);
        in ^= A.x > 0 && B.x <= 0 && A / B > 0;
    }
    return in ? "IN" : "OUT";
}
polygon convex(polygon P) // 求点集P的凸包
{
    std::iter_swap(P.begin(), std::min_element(P.begin(), P.end(), [&](const point &A, const point &B)
                                               { return A.y == B.y ? A.x < B.x : A.y < B.y; }));
    point r = P[0];
    for (auto &i : P)
        i -= r;
    std::sort(P.begin() + 1, P.end(), [&](const point &A, const point &B)
              { return A / B == 0 ? sqr(A) < sqr(B) : A / B > 0; });
    std::size_t suf = 1;
    while (P[P.size() - suf - 1] / P[P.size() - suf] < eps)
        ++suf;
    std::sort(P.end() - suf, P.end(), [&](const point &A, const point &B)
              { return sqr(A) > sqr(B); });
    polygon Q;
    for (auto i : P)
    {
        while (Q.size() >= 2 && Q.end()[-2] / Q.back() + Q.back() / i + i / Q.end()[-2] < 0)
            Q.pop_back();
        Q.push_back(i);
    }
    for (auto &i : Q)
        i += r;
    return Q;
}
double diameter(polygon P) // 求凸多边形P的直径的平方
{
    double res = 0;
    P.insert(P.end(), P.begin(), P.end());
    for (std::size_t i = 0, j = 0; i != P.size(); ++i)
    {
        while ((P[j + 1] - P[i]) * (P[j + 1] - P[i]) > (P[j] - P[i]) * (P[j] - P[i]))
            ++j;
        res = std::max(res, sqr(P[j] - P[i]));
    }
    return res;
}
std::pair<std::vector<line>, polygon> halfPlaneIntersection(std::vector<line> l) // 半平面集的半平面交(如果存在一个凸多边形)
{
    std::sort(l.begin(), l.end());
    l.erase(std::unique(l.begin(), l.end()), l.end());
    std::deque<line> g;
    std::deque<point> h;
    for (const auto &i : l)
    {
        while (!h.empty() && clockwise(i, h.back()) == "CLOCKWISE")
            g.pop_back(), h.pop_back();
        while (!h.empty() && clockwise(i, h.front()) == "CLOCKWISE")
            g.pop_front(), h.pop_front();
        if (!g.empty())
        {
            if (h.empty() && g.back().angle() + PI <= i.angle())
                break;
            h.push_back(cross(g.back(), i));
        }
        g.push_back(i);
    }
    while (!h.empty() && clockwise(g.front(), h.back()) == "CLOCKWISE")
        g.pop_back(), h.pop_back();
    h.push_back(cross(g.back(), g.front()));
    return {std::vector<line>(g.begin(), g.end()), polygon(h.begin(), h.end())};
}
int circleIntersection(circle O, circle P) // 圆O与圆P公切线条数
{
    if (sqr(O.O - P.O) > sqr(O.r + P.r))
        return 4;
    if (sqr(O.O - P.O) == sqr(O.r + P.r))
        return 3;
    if (sqr(O.O - P.O) < sqr(O.r - P.r))
        return 0;
    if (sqr(O.O - P.O) == sqr(O.r - P.r))
        return 1;
    return 2;
}
circle incircle(point A, point B, point C) // 三角形ABC的内接圆
{
    double a = std::sqrt(sqr(B - C)), b = std::sqrt(sqr(A - C)), c = std::sqrt(sqr(B - A));
    return {1 / (a + b + c) * (a * A + b * B + c * C), std::abs(A / B + B / C + C / A) / (a + b + c)};
}
circle circum(point A, point B, point C) // 三角形ABC的外切圆
{
    double a = sqr(A), b = sqr(B), c = sqr(C);
    double S = (A / B + B / C + C / A) * 2;
    return {(~A * (b - c) + ~B * (c - a) + ~C * (a - b)) * (1 / S), std::sqrt(sqr(A - B) * sqr(B - C) * sqr(C - A)) / std::abs(S)};
}
bool iscross(circle O, line a) // 圆O与直线a是否有交
{
    a.A -= O.O;
    a.B -= O.O;
    a.A -= a.B;
    double delta = sqr(a.A * a.B) - sqr(a.A) * sqr(a.B) + sqr(a.A) * sqr(O.r);
    return delta >= 0;
}
line cross(circle O, line a) // 圆O与直线a的交点
{
    a.A -= O.O;
    a.B -= O.O;
    a.A -= a.B;
    double delta = sqr(a.A * a.B) - sqr(a.A) * sqr(a.B) + sqr(a.A) * sqr(O.r);
    assert(delta >= 0);
    delta = std::sqrt(delta);
    return {(-a.A * a.B + delta) / sqr(a.A) * a.A + a.B + O.O,
            (-a.A * a.B - delta) / sqr(a.A) * a.A + a.B + O.O};
}
line cross(circle O, circle P) // 圆O与圆P的交点
{
    point x = (sqr(O.r) - sqr(P.r) + sqr(P.O - O.O)) / (2 * sqr(P.O - O.O)) * (P.O - O.O);
    point y = std::sqrt(sqr(O.r) / sqr(P.O - O.O) - sqr((sqr(O.r) - sqr(P.r) + sqr(P.O - O.O))) / (4 * sqr(sqr(P.O - O.O)))) * ~(P.O - O.O);
    return {O.O + x - y, O.O + x + y};
}
line tangent(circle O, point X) // 点X过圆O的切点
{
    point c = O.O - X, delta = std::sqrt(sqr(c) - sqr(O.r)) * O.r * ~c;
    return {X + ((sqr(c) - sqr(O.r)) * c + delta) * (1 / sqr(c)), X + ((sqr(c) - sqr(O.r)) * c - delta) * (1 / sqr(c))};
}
std::vector<line> tangent(circle O, circle P) // 圆O与圆P的公切线
{
    static line tmp;
    bool flag = false;
    std::vector<line> res;
    auto push = [&](line x)
    { return flag ? res.push_back({x.B, x.A}) : res.push_back(x); };
    if (O.r > P.r)
        std::swap(O, P), flag = true;
    if (sqr(O.O - P.O) > sqr(O.r - P.r))
    {
        tmp = tangent({P.O, P.r - O.r}, O.O);
        push({O.O + ~(tmp.A - O.O) * (O.r / (tmp.A - O.O).abs()), tmp.A + ~(tmp.A - O.O) * (O.r / (tmp.A - O.O).abs())});
        push({O.O - ~(tmp.B - O.O) * (O.r / (tmp.B - O.O).abs()), tmp.B - ~(tmp.B - O.O) * (O.r / (tmp.B - O.O).abs())});
    }
    else if (sqr(O.O - P.O) == sqr(O.r - P.r))
        res.push_back({(O.O * P.r - P.O * O.r) * (1 / (P.r - O.r)), ~(P.O - O.O)});
    if (sqr(O.O - P.O) > sqr(O.r + P.r))
    {
        tmp = tangent({P.O, P.r + O.r}, O.O);
        push({O.O - ~(tmp.A - O.O) * (O.r / (tmp.A - O.O).abs()), tmp.A - ~(tmp.A - O.O) * (O.r / (tmp.A - O.O).abs())});
        push({O.O + ~(tmp.B - O.O) * (O.r / (tmp.B - O.O).abs()), tmp.B + ~(tmp.B - O.O) * (O.r / (tmp.B - O.O).abs())});
    }
    else if (sqr(O.O - P.O) == sqr(O.r + P.r))
        res.push_back({(O.O * P.r + P.O * O.r) * (1 / (O.r + P.r)), ~(P.O - O.O)});
    return res;
}
double areaIntersection(circle O, line a) // 圆O与三角形Oa的交的有向面积
{
    auto adjust = [](double x)
    {
        while (x > PI)
            x -= 2 * PI;
        while (x < -PI)
            x += 2 * PI;
        return x;
    };
    std::vector<point> p;
    p.push_back(a.A);
    p.push_back(a.B);
    if (iscross(O, a))
    {
        line tmp = cross(O, a);
        p.push_back(tmp.A);
        p.push_back(tmp.B);
    }
    std::sort(p.begin(), p.end(), [&](const point &A, const point &B)
              { return A * a.vec() < B * a.vec(); });
    p.erase(std::remove_if(p.begin(), p.end(), [&](const point &X)
                           { return X * a.vec() < a.A * a.vec() || X * a.vec() > a.B * a.vec(); }),
            p.end());
    for (auto &i : p)
        i -= O.O;
    double res = 0;
    for (std::size_t i = 1; i != p.size(); ++i)
        if (sqr(p[i - 1]) < sqr(O.r) + eps && sqr(p[i]) < sqr(O.r) + eps)
            res += p[i - 1] / p[i];
        else
            res += adjust(p[i].angle() - p[i - 1].angle()) * sqr(O.r);
    return res / 2;
}
double areaIntersection(circle O, circle P) // 圆O与圆P的交的面积
{
    auto adjust = [](double x)
    {
        while (x > 2 * PI)
            x -= 2 * PI;
        while (x < 0)
            x += 2 * PI;
        return x;
    };
    if (sqr(O.O - P.O) <= sqr(O.r - P.r))
        return sqr(std::min(O.r, P.r)) * PI;
    if (sqr(O.O - P.O) >= sqr(O.r + P.r))
        return 0;
    line tmp = cross(O, P);
    return (adjust((tmp.B - O.O).angle() - (tmp.A - O.O).angle()) * sqr(O.r) - (O.O / tmp.A + tmp.A / tmp.B + tmp.B / O.O) +
            adjust((tmp.A - P.O).angle() - (tmp.B - P.O).angle()) * sqr(P.r) - (P.O / tmp.B + tmp.B / tmp.A + tmp.A / P.O)) /
           2;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...