大大大大板子

枚举子集

for (int x = s; x; x = (x - 1) & s) {}
View Code

高维前缀和

for (int i = 0; i < m; ++i)
    for (int j = 0; j < (1 << m); ++j)
        if (j & (1 << i)) f[j] += f[j ^ (1 << i)];

for (int i = 0; i < m; ++i)
    for (int j = 0; j < (1 << m); ++j)
        if (!(j & (1 << i))) f[j] += f[j | (1 << i)];
View Code

线性基

void insert(long long x) {
    for (int i = 62; ~i; --i)
        if (x >> i) {
            if (!p[i]) { p[i] = x; break; }
            x ^= p[i];
        }
}
void rebuild() {
    for (int i = 62; ~i; --i)
        for (int j = i - 1; ~j; --j)
            if (p[i] & (1LL << j)) p[i] ^= p[j];
}
View Code

线性求逆元

inv[1] = 1;
for (int i = 2; i <= n; ++i) inv[i] = 1LL * (p - p / i) * inv[p % i] % p;
View Code

欧拉筛

void sieve() {
    np[1] = 1, phi[1] = mu[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!np[i]) p[++tot] = i, phi[i] = i - 1, mu[i] = -1;
        for (int j = 1; j <= tot && i * p[j] <= n; ++j) {
            np[i * p[j]] = 1;
            if (i % p[j] == 0) {
                phi[i * p[j]] = phi[i] * p[j], mu[i * p[j]] = 0;
                break;
            }
            phi[i * p[j]] = phi[i] * (p[j] - 1), mu[i * p[j]] = -mu[i];
        }
    }
}
View Code

文艺平衡树

#include <cstdio>
#include <algorithm>

const int N = 100002;
int a[N], val[N], rev[N], siz[N], fa[N], ch[N][2], rt, cnt, n, m;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
int get(int x) {
    return ch[fa[x]][1] == x;
}
void maintain(int x) {
    siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
}
void tab(int x) {
    rev[x] ^= 1, std::swap(ch[x][0], ch[x][1]);
}
void pushdown(int x) {
    if (ch[x][0]) tab(ch[x][0]);
    if (ch[x][1]) tab(ch[x][1]);
    rev[x] = 0;
}
void build(int &cur, int pre, int l, int r) {
    if (l > r) return;
    cur = ++cnt;
    int mid = (l + r) >> 1;
    val[cur] = a[mid], fa[cur] = pre;
    build(ch[cur][0], cur, l, mid - 1);
    build(ch[cur][1], cur, mid + 1, r);
    maintain(cur);
}
void rotate(int x) {
    int y = fa[x], z = fa[y], k = get(x);
    if (rev[y]) pushdown(y);
    if (rev[x]) pushdown(x);
    if (z) ch[z][get(y)] = x;
    ch[y][k] = ch[x][k ^ 1], ch[x][k ^ 1] = y;
    fa[ch[y][k]] = y, fa[y] = x, fa[x] = z;
    maintain(y), maintain(x);
}
void splay(int x, int z) {
    for (int y; (y = fa[x]) != z; rotate(x))
        if (fa[y] != z) rotate(get(x) ^ get(y) ? x : y);
    if (!z) rt = x;
}
int find(int k) {
    int x = rt;
    for (;;) {
        if (rev[x]) pushdown(x);
        if (siz[ch[x][0]] + 1 == k) return x;
        if (siz[ch[x][0]] >= k) x = ch[x][0];
        else k -= siz[ch[x][0]] + 1, x = ch[x][1];
    }
}
void print(int x) {
    if (rev[x]) pushdown(x);
    if (ch[x][0]) print(ch[x][0]);
    if (1 <= val[x] && val[x] <= n) printf("%d ", val[x]);
    if (ch[x][1]) print(ch[x][1]);
}
int main() {
    n = read(), m = read();
    for (int i = 2; i <= n + 1; ++i) a[i] = i - 1;
    a[1] = 0, a[n + 2] = n + 1, build(rt, 0, 1, n + 2);
    while (m--) {
        int l = read(), r = read();
        l = find(l), r = find(r + 2), splay(l, 0), splay(r, l), tab(ch[r][0]);
    }
    print(rt);
    return 0;
}
View Code

主席树

#include <cstdio>
#include <algorithm>

const int N = 200002, M = 3800002;
int a[N], b[N], sum[M], ls[M], rs[M], rt[N], cnt;

int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x * f;
}
int find(int x, int l, int r) {
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (b[mid] == x) return mid;
        if (b[mid] < x) l = mid + 1;
        else r = mid - 1;
    }
}
void insert(int &x, int y, int l, int r, int p) {
    x = ++cnt, sum[x] = sum[y] + 1;
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (p <= mid) rs[x] = rs[y], insert(ls[x], ls[y], l, mid, p);
    if (mid < p) ls[x] = ls[y], insert(rs[x], rs[y], mid + 1, r, p);
}
int query(int x, int y, int l, int r, int k) {
    if (l == r) return b[l];
    int mid = (l + r) >> 1;
    if (sum[ls[x]] - sum[ls[y]] >= k) return query(ls[x], ls[y], l, mid, k);
    return query(rs[x], rs[y], mid + 1, r, k - sum[ls[x]] + sum[ls[y]]);
}
int main() {
    int n = read(), m = read();
    for (int i = 1; i <= n; ++i) a[i] = b[i] = read();
    std::sort(b + 1, b + n + 1);
    for (int i = 1; i <= n; ++i) insert(rt[i], rt[i - 1], 1, n, find(a[i], 1, n));
    while (m--) {
        int l = read(), r = read(), k = read();
        printf("%d\n", query(rt[r], rt[l - 1], 1, n, k));
    }
    return 0;
}
View Code

二维线段树

#include <cstdio>
#include <algorithm>

int ans, n, m, q;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
struct Node {
    int mx[2050], tag[2050];
    void update(int cur, int l, int r, int L, int R, int x) {
        mx[cur] = std::max(mx[cur], x);
        if (L <= l && r <= R) { tag[cur] = std::max(tag[cur], x); return; }
        int mid = (l + r) >> 1;
        if (L <= mid) update(cur << 1, l, mid, L, R, x);
        if (mid < R) update(cur << 1 | 1, mid + 1, r, L, R, x);
    }
    int query(int cur, int l, int r, int L, int R) {
        if (L <= l && r <= R) return mx[cur];
        int mid = (l + r) >> 1, res = tag[cur];
        if (L <= mid) res = std::max(res, query(cur << 1, l, mid, L, R));
        if (mid < R) res = std::max(res, query(cur << 1 | 1, mid + 1, r, L, R));
        return res;
    }
} mx[2050], tag[2050];
void update(int cur, int l, int r, int L, int R, int yl, int yr, int x) {
    mx[cur].update(1, 1, m, yl, yr, x);
    if (L <= l && r <= R) { tag[cur].update(1, 1, m, yl, yr, x); return; }
    int mid = (l + r) >> 1;
    if (L <= mid) update(cur << 1, l, mid, L, R, yl, yr, x);
    if (mid < R) update(cur << 1 | 1, mid + 1, r, L, R, yl, yr, x);
}
int query(int cur, int l, int r, int L, int R, int yl ,int yr) {
    if (L <= l && r <= R) return mx[cur].query(1, 1, m, yl, yr);
    int mid = (l + r) >> 1, res = tag[cur].query(1, 1, m, yl, yr);
    if (L <= mid) res = std::max(res, query(cur << 1, l, mid, L, R, yl, yr));
    if (mid < R) res = std::max(res, query(cur << 1 | 1, mid + 1, r, L, R, yl, yr));
    return res;
}
int main() {
    n = read() + 1, m = read() + 1, q = read();
    while (q--) {
        int d = read(), s = read(), h = read(), x = read() + 1, y = read() + 1;
        int tmp = query(1, 1, n, x, x + d - 1, y, y + s - 1) + h;
        update(1, 1, n, x, x + d - 1, y, y + s - 1, tmp), ans = std::max(ans, tmp);
    }
    printf("%d\n", ans);
    return 0;
}
View Code

二逼平衡树

#include <cstdio>
#include <cstdlib>
#include <algorithm>

const int N = 1700002, INF = 0x7fffffff;
int n, m, a[50002], cnt, rt[131074], ch[N][2], val[N], rnd[N], num[N], siz[N];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
void maintain(int x) {
    siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + num[x];
}
void rotate(int &x, int k) {
    int y = ch[x][k ^ 1];
    ch[x][k ^ 1] = ch[y][k], ch[y][k] = x;
    maintain(x), maintain(y), x = y;
}
void insert(int &x, int y) {
    if (!x) { x = ++cnt, val[x] = y, num[x] = siz[x] = 1, rnd[x] = rand(); return; }
    if (val[x] == y) { ++num[x], ++siz[x]; return; }
    int k = y > val[x];
    insert(ch[x][k], y);
    if (rnd[ch[x][k]] > rnd[x]) rotate(x, k ^ 1);
    maintain(x);
}
void Insert(int x, int l, int r, int p, int v) {
    insert(rt[x], v);
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (p <= mid) Insert(x << 1, l, mid, p, v);
    else Insert(x << 1 | 1, mid + 1, r, p, v);
}
int rank(int x, int k) {
    if (!x) return 0;
    if (val[x] == k) return siz[ch[x][0]];
    if (val[x] > k) return rank(ch[x][0], k);
    return siz[ch[x][0]] + num[x] + rank(ch[x][1], k);
}
int Rank(int x, int l, int r, int L, int R, int k) {
    if (L <= l && r <= R) return rank(rt[x], k);
    int mid = (l + r) >> 1, res = 0;
    if (L <= mid) res = Rank(x << 1, l, mid, L, R, k);
    if (mid < R) res += Rank(x << 1 | 1, mid + 1, r, L, R, k);
    return res;
}
int Kth(int L, int R, int k) {
    int l = 0, r = 1e8;
    while (l < r) {
        int mid = (l + r + 1) >> 1, tmp = Rank(1, 1, n, L, R, mid);
        if (tmp < k) l = mid; else r = mid - 1;
    }
    return l;
}
void del(int &x, int y) {
    if (!x) return;
    if (val[x] == y) {
        if (num[x] > 1) { --num[x], --siz[x]; return; }
        if (!ch[x][0]) { x = ch[x][1]; return; }
        if (!ch[x][1]) { x = ch[x][0]; return; }
        int k = rnd[ch[x][0]] > rnd[ch[x][1]];
        rotate(x, k), del(ch[x][k], y);
    } else del(ch[x][y > val[x]], y);
    maintain(x);
}
void Modify(int x, int l, int r, int p, int v) {
    del(rt[x], a[p]), insert(rt[x], v);
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (p <= mid) Modify(x << 1, l, mid, p, v);
    else Modify(x << 1 | 1, mid + 1, r, p, v);
}
int pre(int x, int y) {
    if (!x) return -INF;
    if (val[x] >= y) return pre(ch[x][0], y);
    return std::max(val[x], pre(ch[x][1], y));
}
int Pre(int x, int l, int r, int L, int R, int k) {
    if (L <= l && r <= R) return pre(rt[x], k);
    int mid = (l + r) >> 1, res = -INF;
    if (L <= mid) res = Pre(x << 1, l, mid, L, R, k);
    if (mid < R) res = std::max(res, Pre(x << 1 | 1, mid + 1, r, L, R, k));
    return res;
}
int suf(int x, int y) {
    if (!x) return INF;
    if (val[x] <= y) return suf(ch[x][1], y);
    return std::min(val[x], suf(ch[x][0], y));
}
int Suf(int x, int l, int r, int L, int R, int k) {
    if (L <= l && r <= R) return suf(rt[x], k);
    int mid = (l + r) >> 1, res = INF;
    if (L <= mid) res = Suf(x << 1, l, mid, L, R, k);
    if (mid < R) res = std::min(res, Suf(x << 1 | 1, mid + 1, r, L, R, k));
    return res;
}
int main() {
    n = read(), m = read();
    for (int i = 1; i <= n; ++i) a[i] = read(), Insert(1, 1, n, i, a[i]);
    while (m--) {
        int opt = read();
        if (opt == 1) {
            int l = read(), r = read(), k = read();
            printf("%d\n", Rank(1, 1, n, l, r, k) + 1);
        } else if (opt == 2) {
            int l = read(), r = read(), k = read();
            printf("%d\n", Kth(l, r, k));
        } else if (opt == 3) {
            int p = read(), k = read();
            Modify(1, 1, n, p, k), a[p] = k;
        } else if (opt == 4) {
            int l = read(), r = read(), k = read();
            printf("%d\n", Pre(1, 1, n, l, r, k));
        } else {
            int l = read(), r = read(), k = read();
            printf("%d\n", Suf(1, 1, n, l, r, k));
        }
    }
    return 0;
}
View Code

树状数组套主席树

#include <cstdio>
#include <algorithm>

const int N = 100002, M = 64800002;
struct Node { int a, b, c; } q[N];
int a[N], b[N << 1], cnt, sum[M], rt[N], ls[M], rs[M], L[20], R[20];

int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x * f;
}
int find(int x) {
    int l = 1, r = b[0];
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (b[mid] == x) return mid;
        if (b[mid] < x) l = mid + 1;
        else r = mid - 1;
    }
}
void update(int &x, int l, int r, int p, int v) {
    if (!x) x = ++cnt;
    sum[x] += v;
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (p <= mid) update(ls[x], l, mid, p, v);
    else update(rs[x], mid + 1, r, p, v);
}
int query(int l, int r, int k) {
    if (l == r) return b[l];
    int mid = (l + r) >> 1, tmp = 0;
    for (int i = 1; i <= R[0]; ++i) tmp += sum[ls[R[i]]];
    for (int i = 1; i <= L[0]; ++i) tmp -= sum[ls[L[i]]];
    if (tmp >= k) {
        for (int i = 1; i <= R[0]; ++i) R[i] = ls[R[i]];
        for (int i = 1; i <= L[0]; ++i) L[i] = ls[L[i]];
        return query(l, mid, k);
    }
    for (int i = 1; i <= R[0]; ++i) R[i] = rs[R[i]];
    for (int i = 1; i <= L[0]; ++i) L[i] = rs[L[i]];
    return query(mid + 1, r, k - tmp);
}
int main() {
    int n = read(), m = read(); char opt[3] = {};
    for (int i = 1; i <= n; ++i) a[i] = b[++cnt] = read();
    for (int i = 1; i <= m; ++i) {
        scanf("%s", opt), q[i].a = read(), q[i].b = read();
        if (opt[0] == 'Q') q[i].c = read(); else b[++cnt] = q[i].b;
    }
    std::sort(b + 1, b + cnt + 1), b[0] = 1;
    for (int i = 2; i <= cnt; ++i) if (b[i] > b[i - 1]) b[++b[0]] = b[i];
    cnt = 0;
    for (int i = 1; i <= n; ++i) {
        int x = find(a[i]);
        for (int j = i; j <= n; j += j & (-j)) update(rt[j], 1, b[0], x, 1);
    }
    for (int i = 1; i <= m; ++i) {
        if (q[i].c) {
            L[0] = R[0] = 0;
            for (int j = q[i].a - 1; j; j -= j & (-j)) L[++L[0]] = rt[j];
            for (int j = q[i].b; j; j -= j & (-j)) R[++R[0]] = rt[j];
            printf("%d\n", query(1, b[0], q[i].c));
        } else {
            int x = find(a[q[i].a]), y = find(q[i].b);
            for (int j = q[i].a; j <= n; j += j & (-j))
                update(rt[j], 1, b[0], x, -1), update(rt[j], 1, b[0], y, 1);
            a[q[i].a] = q[i].b;
        }
    }
    return 0;
}
View Code

LCT

#include <cstdio>
#include <algorithm>

const int N = 300002;
int a[N], fa[N], ch[N][2], rev[N], sum[N];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
int get(int x) {
    return ch[fa[x]][1] == x;
}
bool isroot(int x) {
    return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}
void tab(int x) {
    std::swap(ch[x][0], ch[x][1]), rev[x] ^= 1;
}
void pushdown(int x) {
    if (ch[x][0]) tab(ch[x][0]);
    if (ch[x][1]) tab(ch[x][1]);
    rev[x] = 0;
}
void maintain(int x) {
    sum[x] = sum[ch[x][0]] ^ sum[ch[x][1]] ^ a[x];
}
void rotate(int x) {
    int y = fa[x], z = fa[y], k = get(x);
    if (!isroot(y)) ch[z][get(y)] = x;
    ch[y][k] = ch[x][k ^ 1], ch[x][k ^ 1] = y;
    fa[ch[y][k]] = y, fa[y] = x, fa[x] = z;
    maintain(y), maintain(x);
}
void push(int x) {
    if (!isroot(x)) push(fa[x]);
    if (rev[x]) pushdown(x);
}
void splay(int x) {
    push(x);
    for (int y; !isroot(x); rotate(x))
        if (!isroot(y = fa[x])) rotate(get(x) ^ get(y) ? x : y);
}
void access(int x) {
    for (int y = 0; x; y = x, x = fa[x])
        splay(x), ch[x][1] = y, maintain(x);
}
void make(int x) {
    access(x), splay(x), tab(x);
}
int find(int x) {
    access(x), splay(x);
    while (ch[x][0]) x = ch[x][0];
    return x;
}
void link(int x, int y) {
    if (find(x) == find(y)) return;
    make(x), access(y), splay(y), fa[x] = y, maintain(y);
}
void cut(int x, int y) {
    make(x), access(y), splay(y);
    if (ch[y][0] != x) return;
    ch[y][0] = fa[x] = 0, maintain(y);
}
int query(int x, int y) {
    make(x), access(y), splay(y);
    return sum[y];
}
int main() {
    int n = read(), m = read();
    for (int i = 1; i <= n; ++i) a[i] = read();
    while (m--) {
        int opt = read(), x = read(), y = read();
        if (opt == 0) printf("%d\n", query(x, y));
        else if (opt == 1) link(x, y);
        else if (opt == 2) cut(x, y);
        else splay(x), sum[x] ^= a[x] ^ y, a[x] = y;
    }
    return 0;
}
View Code

线段树合并

int merge(int x, int y) {
    if (!x) return y;
    if (!y) return x;
    sum[x] += sum[y];
    lson[x] = merge(lson[x], lson[y]);
    rson[x] = merge(rson[x], rson[y]);
    return x;
}
View Code

单调队列优化多重背包

设 $w[i]$ 表示物品重量,$v[i]$ 表示价值,$c[i]$ 表示数量,我们知道朴素状态转移方程:

$$f[i][j]=\max\{f[i-1][j-k*w[i]]+k*v[i]\}(k\le c[i])$$

设 $a=j\bmod w[i], b = \left\lfloor\frac{j}{w[i]}\right\rfloor$,有

$$f[i][j]=\max\{f[i-1][a+k*w[i]]-k*v[i]\}+b*v[i](b-c[i]\le k \le b)$$

其中第 $i$ 个物品取了 $\left\lfloor\frac{j-a-k*w[i]}{w[i]}\right\rfloor=b-\left\lfloor\frac{a}{w[i]}\right\rfloor-k=b-k$ 个。

我们先枚举 $i$,再枚举 $a$,再枚举 $k$,这样 $\max$ 里面就只和 $k$ 有关了,单调队列优化。

#include <cstdio>
#include <algorithm>

int n, m, q[7002][2], f[7002];

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1, w, v, c; i <= n; ++i) {
        scanf("%d%d%d", &w, &v, &c);
        if (c > m / w) c = m / w;
        for (int a = 0; a < w; ++a) {
            int h = 1, t = 0;
            for (int k = 0; k <= m / w; ++k) { //对于当前来说是b,对于队列中是k,因此这样升序枚举保证了k<=b
                int now = f[a + k * w] - k * v;
                while (h <= t && q[t][1] <= now) --t;
                q[++t][1] = now, q[t][0] = k; //先放入
                while (h <= t && k - q[h][0] > c) ++h;
                f[a + k * w] = std::max(f[a + k * w], q[h][1] + k * v); //后求值
            }
        }
    }
    printf("%d\n", f[m]);
    return 0;
}
View Code

树上背包优化

void dfs(int u, int f) {
    for (int i = 1; i + v[u] <= m; ++i) dp[u][i + v[u]] = dp[f][i];
    for (int i = head[u]; i; i = e[i].nxt) if (e[i].v != f) dfs(e[i].v, u);
    for (int i = 1; i <= m; ++i) if ((dp[f][i] += dp[u][i]) >= mod) dp[f][i] -= mod;
}
View Code

dsu on tree

思路:轻重链剖分,先 $dfs$ 当前点的轻儿子,回溯到当前点时暴力删除贡献,然后 $dfs$ 重儿子,不删除贡献,最后重新 $dfs$ 轻儿子累计贡献。由于一个树最多有 $\log n$ 条重链,因此每个结点最多被重复访问 $\log n$ 次,时间复杂度 $n\log n$。

缩点

void tarjan(int u) {
    dfn[u] = low[u] = ++dfs_clock, sta[++top] = u, ins[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt) {
        if (!dfn[e[i].v]) tarjan(e[i].v), low[u] = std::min(low[u], low[e[i].v]);
        else if (ins[e[i].v]) low[u] = std::min(low[u], dfn[e[i].v]);
    }
    if (dfn[u] == low[u]) {
        col[u] = ++cnt, ins[u] = 0;
        while (sta[top] != u) col[sta[top]] = cnt, ins[sta[top]] = 0, --top;
        --top;
    }
}
View Code

割点

void tarjan(int u, int f) {
    dfn[u] = low[u] = ++dfs_clock;
    int son = 0;
    for (int i = head[u]; i; i = e[i].nxt) {
        if (!dfn[e[i].v]) {
            ++son, tarjan(e[i].v, u);
            low[u] = std::min(low[u], low[e[i].v]);
            if (low[e[i].v] >= dfn[u]) iscut[u] = 1;
        } else low[u] = std::min(low[u], dfn[e[i].v]);
    }
    if (!f && son == 1) iscut[u] = 0;
}
View Code

点双

void tarjan(int u) {
    low[u] = dfn[u] = ++dfs_clock, siz[u] = 1, sta[++top] = u;
    for (int i = head[u]; i; i = e[i].nxt) {
        if (!dfn[e[i].v]) {
            tarjan(e[i].v), low[u] = min(low[u], low[e[i].v]);
            if (dfn[u] <= low[e[i].v]) {
                v[++cnt] = 1;
                do {
                    ++v[cnt], siz[cnt] += siz[sta[top]];
                    adde2(cnt, sta[top]), adde2(sta[top], cnt);
                } while (sta[top--] != e[i].v);
                siz[u] += siz[cnt], adde2(cnt, u), adde2(u, cnt);
            }
        } else low[u] = min(low[u], dfn[e[i].v]);
    }
}
View Code

边双

 

圆方树

 

虚树

#include <cstdio>
#include <cstring>
#include <algorithm>

const int N = 250005;
typedef long long LL;
struct Edge { int v, w, nxt; } e[N<<1];
struct Edge2 { int v, nxt; } e2[N];
int a[N], head[N], tot, head2[N], tot2, dfn[N], siz[N], dep[N], tp[N], fa[N], son[N], dfs_clock, sta[N], top; LL mn[N];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
LL min(LL x, LL y) {
    return x < y ? x : y;
}
bool cmp(int a, int b) {
    return dfn[a] < dfn[b];
}
void adde(int u, int v, int w) {
    e[++tot].nxt = head[u], head[u] = tot;
    e[tot].v = v, e[tot].w = w;
}
void adde2(int u, int v) {
    e2[++tot2].nxt = head2[u];
    head2[u] = tot2, e2[tot2].v = v;
}
void dfs1(int u, int f, int d) {
    siz[u] = 1, fa[u] = f, dep[u] = d;
    for (int i = head[u]; i; i = e[i].nxt) {
        if (e[i].v == f) continue;
        mn[e[i].v] = min(mn[u], e[i].w);
        dfs1(e[i].v, u, d + 1), siz[u] += siz[e[i].v];
        if (siz[e[i].v] > siz[son[u]]) son[u] = e[i].v;
    }
}
void dfs2(int u, int t) {
    tp[u] = t, dfn[u] = ++dfs_clock;
    if (son[u]) dfs2(son[u], t);
    for (int i = head[u]; i; i = e[i].nxt)
        if (e[i].v != fa[u] && e[i].v != son[u]) dfs2(e[i].v, e[i].v);
}
int getlca(int x, int y) {
    while (tp[x] != tp[y]) {
        if (dep[tp[x]] > dep[tp[y]]) x = fa[tp[x]];
        else y = fa[tp[y]];
    }
    if (dep[x] < dep[y]) return x; return y;
}
void insert(int x) {
    if (top == 1) { sta[++top] = x; return; }
    int lca = getlca(x, sta[top]);
    if (lca == sta[top]) return;
    while (top > 1 && dfn[sta[top-1]] >= dfn[lca]) adde2(sta[top-1], sta[top]), --top;
    if (lca != sta[top]) adde2(lca, sta[top]), sta[top] = lca;
    sta[++top] = x;
}
LL dp(int u) {
    if (!head2[u]) return mn[u]; LL res = 0;
    for (int i = head2[u]; i; i = e2[i].nxt) res += dp(e2[i].v);
    head2[u] = 0;
    return min(res, mn[u]);
}

int main() {
    int n = read();
    for (int i = 1, u, v, w; i < n; ++i)
        u = read(), v = read(), w = read(), adde(u, v, w), adde(v, u, w);
    mn[1] = 1e18, dfs1(1, 0, 1), dfs2(1, 1);
    int m = read();
    while (m--) {
        int k = read(); tot2 = 0;
        for (int i = 1; i <= k; ++i) a[i] = read();
        std::sort(a + 1, a + k + 1, cmp);
        sta[top=1] = 1;
        for (int i = 1; i <= k; ++i) insert(a[i]);
        while (top) adde2(sta[top-1], sta[top]), --top;
        printf("%lld\n", dp(1));
    }
    return 0;
}
View Code

2-SAT

#include <cstdio>
#include <vector>

const int N = 16005;
std::vector<int> G[N];
int col[N], sta[N], top, n, m;

int get(int x) {
    if (x & 1) return x + 1; return x - 1;
}
bool dfs(int x) { //染色 
    if (col[x]) return col[x] % 2; //染1不矛盾,染2矛盾 
    col[x] = 1, col[get(x)] = 2;
    sta[++top] = x; //记录一组染色 
    int sz = G[x].size();
    for (int i = 0; i < sz; ++i) 
        if (!dfs(G[x][i])) return false;
    return true;
}
bool sat() {
    for (int i = 1; i <= n; ++i) { //枚举所有人 
        if (col[i]) continue;
        top = 0;
        if (!dfs(i)) { //i染色失败 
            for (int j = 1; j <= top; ++j) //清空本次染色 
                col[sta[j]] = col[get(sta[j])] = 0;
            if (!dfs(get(i))) return false;
        }
    }
    return true;
}

int main() {
    while (~scanf("%d%d", &n, &m)) {
        n <<= 1;
        for (int i = 1; i <= n; ++i) G[i].clear(), col[i] = 0;
        for (int i = 1; i <= m; ++i) {
            int u, v; scanf("%d%d", &u, &v);
            G[u].push_back(get(v));
            G[v].push_back(get(u));
        }
        if (sat()) {
            for (int i = 1; i <= n; ++i)
                if (col[i] == 1) printf("%d\n", i);
           } else puts("NIE");
    }
    return 0;
}
View Code

KMP

#include <cstdio>
#include <cstring>

char s[1000002], w[1000002]; int n, m, nxt[1000002];

void getnxt() {
    for (int i = 1; i < m; ++i) {
        int j = nxt[i];
        while (w[i] != w[j] && j) j = nxt[j];
        if (w[i] == w[j]) nxt[i + 1] = j + 1;
    }
}
void kmp() {
    for (int i = 0, j = 0; i < n; ++i) {
        while (s[i] != w[j] && j) j = nxt[j];
        if (s[i] == w[j]) ++j;
        if (j == m) printf("%d\n", i - m + 2);
    }
}
int main() {
    scanf("%s%s", &s, &w), n = strlen(s), m = strlen(w);
    getnxt(), kmp();
    for (int i = 1; i <= m; ++i) printf("%d ", nxt[i]);
    return 0;
}
View Code

Manacher

#include <cstdio>
#include <cstring>
#include <algorithm>

char s[11000005]; int R[11000002], ans, n;

void manacher() {
    int mx = 0, mid = 0;
    for (int i = 1; i <= n; ++i) {
        if (i <= mx) R[i] = std::min(R[(mid << 1) - i], mx - i + 1);
        else R[i] = 1;
        while (s[i - R[i]] == s[i + R[i]]) ++R[i];
        if (i + R[i] - 1 > mx) mx = i + R[i] - 1, mid = i;
        ans = std::max(ans, (R[i] << 1) - 1);
    }
    mx = mid = 0;
    for (int i = 1; i < n; ++i) {
        if (i <= mx) R[i] = std::min(R[(mid << 1) - i], mx - i);
        else R[i] = 0;
        while (s[i - R[i]] == s[i + R[i] + 1]) ++R[i];
        if (i + R[i] > mx) mx = i + R[i], mid = i;
        ans = std::max(ans, R[i] << 1);
    }
}

int main() {
    scanf("%s", s + 1), n = strlen(s + 1);
    s[0] = '&', s[n + 1] = '$';
    manacher(), printf("%d\n", ans);
    return 0;
}
View Code

AC自动机

#include <cstdio>
#include <queue>
#include <cstring>

const int N = 200005;
struct Edge { int v, nxt; } e[N], g[N];
char s[N]; int head1[N], head2[N], tot1, tot2, sum[N], ans[N], siz[N], dfn[N], dfs_clock, q[N], t, fa[N], cnt, tr[N][26], ch[N][26], fail[N];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
void add1(int u, int v) {
    e[++tot1].nxt = head1[u], head1[u] = tot1, e[tot1].v = v;
}
void add2(int u, int v) {
    g[++tot2].nxt = head2[u], head2[u] = tot2, g[tot2].v = v;
}
void update(int x, int y) {
    while (x <= N - 5) sum[x] += y, x += x & (-x);
}
int query(int x) {
    int res = 0;
    while (x) res += sum[x], x -= x & (-x);
    return res;
}
void insert() {
    int x = 0, n = strlen(s);
    for (int i = 0; i < n; ++i) {
        if (s[i] == 'P') q[++t] = x;
        else if (s[i] == 'B') x = fa[x];
        else {
            if (!ch[x][s[i]-'a']) tr[x][s[i]-'a'] = ch[x][s[i]-'a'] = ++cnt;
            fa[ch[x][s[i]-'a']] = x, x = ch[x][s[i]-'a'];
        }
    }
}
void getfail() {
    std::queue<int> Q;
    for (int i = 0; i < 26; ++i) if (ch[0][i]) add1(0, ch[0][i]), Q.push(ch[0][i]);
    while (!Q.empty()) {
        int x = Q.front(); Q.pop();
        for (int i = 0; i < 26; ++i) {
            if (!ch[x][i]) ch[x][i] = ch[fail[x]][i];
            else {
                fail[ch[x][i]] = ch[fail[x]][i];
                add1(fail[ch[x][i]], ch[x][i]), Q.push(ch[x][i]);
            }
        }
    }
}
void dfs1(int u) {
    dfn[u] = ++dfs_clock, siz[u] = 1;
    for (int i = head1[u]; ~i; i = e[i].nxt)
        dfs1(e[i].v), siz[u] += siz[e[i].v];
}
void dfs2(int u) {
    update(dfn[u], 1);
    for (int i = head2[u]; ~i; i = g[i].nxt)
        ans[i] = query(dfn[g[i].v] + siz[g[i].v] - 1) - query(dfn[g[i].v] - 1);
    for (int i = 0; i < 26; ++i) if (tr[u][i]) dfs2(ch[u][i]);
    update(dfn[u], -1);
}

int main() {
    memset(head1, -1, sizeof head1);
    memset(head2, -1, sizeof head2);
    scanf("%s", s), insert();
    getfail();
    int T = read(); dfs1(0);
    for (int i = 1, x, y; i <= T; ++i)
        x = read(), y = read(), add2(q[y], q[x]);
    dfs2(0);
    for (int i = 1; i <= T; ++i) printf("%d\n", ans[i]);
    return 0;
}
View Code

后缀数组

#include <cstdio>
#include <cstring>
#include <algorithm>

const int N = 1000005;
int n, m = 123, c[N], x[N], y[N], sa[N], h[N]; char s[N];

void build() {
    for (int i = 0; i < n; ++i) ++c[x[i] = s[i]];
    for (int i = 1; i < m; ++i) c[i] += c[i - 1];
    for (int i = n - 1; ~i; --i) sa[--c[x[i]]] = i;
    for (int k = 1; k <= n; k <<= 1) {
        int p = 0;
        for (int i = n - k; i < n; ++i) y[p++] = i;
        for (int i = 0; i < n; ++i) if (sa[i] >= k) y[p++] = sa[i] - k;
        for (int i = 0; i < m; ++i) c[i] = 0;
        for (int i = 0; i < n; ++i) ++c[x[y[i]]];
        for (int i = 1; i < m; ++i) c[i] += c[i - 1];
        for (int i = n - 1; ~i; --i) sa[--c[x[y[i]]]] = y[i];
        std::swap(x, y), p = 1, x[sa[0]] = 0;
        for (int i = 1; i < n; ++i)
            x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && (sa[i - 1] + k < n ? y[sa[i - 1] + k] : -1) == (sa[i] + k < n ? y[sa[i] + k] : -1) ? p - 1 : p++;
        if (p >= n) break; m = p;
    }
}
void height() {
    int k = 0;
    for (int i = 0; i < n; ++i) {
        if (!x[i]) continue;
        if (k) --k;
        int j = sa[x[i] - 1];
        while (i + k < n && j + k < n && s[i + k] == s[j + k]) ++k;
        h[x[i]] = k;
    }
}
int main() {
    scanf("%s", s), n = strlen(s), build();
    for (int i = 0; i < n; ++i) printf("%d ", sa[i] + 1);
    return 0;
}
View Code

后缀自动机

#include <cstdio>
#include <vector>
#include <cstring>

const int N = 2000005;
int sz = 1, L[N], ch[N][10], fa[N];
int color[100005], dgr[100005];
std::vector<int> G[100005];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
int insert(int c, int p) {
    int np = ++sz; L[np] = L[p] + 1;
    for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
    if (!p) fa[np] = 1;
    else {
        int q = ch[p][c];
        if (L[q] == L[p] + 1) fa[np] = q;
        else {
            int nq = ++sz; L[nq] = L[p] + 1;
            memcpy(ch[nq], ch[q], sizeof ch[q]);
            fa[nq] = fa[q], fa[q] = fa[np] = nq;
            for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
        }
    }
    return np;
}
void dfs(int u, int fa, int pre) {
    int now = insert(color[u], pre); //广义SAM记录前驱结点 
    int sz = G[u].size();
    for (int i = 0; i < sz; ++i)
        if (G[u][i] != fa) dfs(G[u][i], u, now);
}

int main() {
    int n = read(), c = read();
    for (int i = 1; i <= n; ++i) color[i] = read();
    for (int i = 1; i < n; ++i) {
        int u = read(), v = read();
        G[u].push_back(v), ++dgr[u];
        G[v].push_back(u), ++dgr[v];
    }
    for (int i = 1; i <= n; ++i)
        if (dgr[i] == 1) dfs(i, 0, 1);
    long long ans = 0;
    for (int i = 1; i <= sz; ++i)
        ans += L[i] - L[fa[i]];
    printf("%lld\n", ans);
    return 0;
}
View Code

回文自动机

#include <cstdio>
#include <cstring>

typedef long long ll;
const int N = 300010;

int ch[N][26], fail[N], len[N], val[N], n, pre, np, i;
char s[N]; ll ans;

ll max(ll x, ll y) {
    if (x >= y) return x; return y;
}
int get(int x) {
    while (s[i-len[x]-1] != s[i]) x = fail[x];
    return x;
}
void insert(int c) {
    int p = get(pre);
    if (!ch[p][c]) {
        fail[++np] = ch[get(fail[p])][c];
        ch[p][c] = np, len[np] = len[p] + 2;
    }
    ++val[ch[p][c]], pre = ch[p][c];
}

int main() {
    scanf("%s", s + 1);
    n = strlen(s + 1);
    fail[0] = np = 1, len[1] = -1;
    for (i = 1; i <= n; ++i) insert(s[i] - 'a');
    for (int i = np; i > 1; --i) {
        val[fail[i]] += val[i];
        ans = max(ans, 1LL * val[i] * len[i]);
    }
    printf("%lld\n", ans);
    return 0;
}
View Code

最小表示法

#include <cstdio>
#define min(x, y) x < y ? x : y

int n, a[300005];

int exp() {
    int i = 0, j = 1, k = 0;
    while (i < n && j < n && k < n) {
        int t = a[(i+k)%n] - a[(j+k)%n];
        if (!t) ++k;
        else {
            if (t > 0) i += k + 1;
            else j += k + 1;
            if (i == j) ++j;
            k = 0;
        }
    }
    return min(i, j);
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    int t = exp();
    for (int i = 0; i < n; ++i)
        printf("%d ", a[(t+i)%n]);
    return 0;
}
View Code

Dinic

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

const int N = 10002, INF = 0x7fffffff;
struct Edge { int v, c, f, nxt; } e[200002];
int head[N], d[N], cur[N], tot = 1, n, m, S, T; std::queue<int> q;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
void adde(int u, int v, int c) {
    e[++tot].nxt = head[u], head[u] = tot, e[tot].v = v, e[tot].c = c;
    e[++tot].nxt = head[v], head[v] = tot, e[tot].v = u, e[tot].c = 0;
}
bool bfs() {
    bool vis[N] = {}; vis[S] = 1, q.push(S);
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int i = head[u]; i; i = e[i].nxt)
            if (!vis[e[i].v] && e[i].c > e[i].f)
                d[e[i].v] = d[u] + 1, vis[e[i].v] = 1, q.push(e[i].v);
    }
    return vis[T];
}
int dfs(int u, int a) {
    if (u == T) return a;
    int flow = 0, x;
    for (int &i = cur[u]; i; i = e[i].nxt)
        if (d[u] + 1 == d[e[i].v] && e[i].c > e[i].f && (x = dfs(e[i].v, std::min(a, e[i].c - e[i].f)))) {
            e[i].f += x, e[i ^ 1].f -= x, flow += x, a -= x;
            if (a == 0) break;
        }
    return flow;
}
int dinic() {
    int flow = 0;
    while (bfs()) memcpy(cur, head, (n + 1) << 2), flow += dfs(S, INF);
    return flow;
}
int main() {
    n = read(), m = read(), S = read(), T = read();
    for (int i = 1, u, v, c; i <= m; ++i) u = read(), v = read(), c = read(), adde(u, v, c);
    printf("%d\n", dinic());
    return 0;
}
View Code

ZKW费用流

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

const int N = 5002, INF = 0x3f3f3f3f;
struct Edge { int v, c, w, f, nxt; } e[100002];
int head[N], d[N], cur[N], vis[N], tot = 1, n, m, S, T, cost; std::queue<int> q;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
void adde(int u, int v, int c, int w) {
    e[++tot].nxt = head[u], head[u] = tot, e[tot].v = v, e[tot].w = w, e[tot].c = c;
    e[++tot].nxt = head[v], head[v] = tot, e[tot].v = u, e[tot].w = -w;
}
bool bfs() {
    memset(vis, 0, (n + 1) << 2), memset(d, 0x3f, (n + 1) << 2), d[S] = 0, q.push(S);
    while (!q.empty()) {
        int u = q.front(); q.pop(), vis[u] = 0;
        for (int i = head[u]; i; i = e[i].nxt)
            if (d[e[i].v] > d[u] + e[i].w && e[i].c > e[i].f) {
                d[e[i].v] = d[u] + e[i].w;
                if (!vis[e[i].v]) q.push(e[i].v), vis[e[i].v] = 1;
            }
    }
    return d[T] < INF;
}
int dfs(int u, int a) {
    if (u == T) return a;
    int flow = 0, x; vis[u] = 1;
    for (int &i = cur[u]; i; i = e[i].nxt)
        if (!vis[e[i].v] && e[i].c > e[i].f && d[e[i].v] == d[u] + e[i].w && (x = dfs(e[i].v, std::min(a, e[i].c - e[i].f)))) {
            e[i].f += x, e[i ^ 1].f -= x, flow += x, a -= x, cost += x * e[i].w;
            if (a == 0) break;
        }
    return flow;
}
int zkw() {
    int flow = 0;
    while (bfs()) memcpy(cur, head, (n + 1) << 2), flow += dfs(S, INF);
    return flow;
}
int main() {
    n = read(), m = read(), S = read(), T = read();
    for (int i = 1, u, v, c, w; i <= m; ++i) u = read(), v = read(), c = read(), w = read(), adde(u, v, c, w);
    printf("%d ", zkw()), printf("%d\n", cost);
    return 0;
}
View Code

高斯消元

#include <cstdio>
#include <algorithm>

int n; double a[15][15], b[15];

double fabs(double x) {
    return x < 0 ? -x : x;
}

void gauss() {
    for (int i = 1; i <= n; ++i) {
        int k = i;
        for (int j = i + 1; j <= n; ++j)
            if (fabs(a[j][i]) > fabs(a[k][i])) k = j;
        std::swap(a[i], a[k]);
        for (int j = n + 1; j >= i; --j) a[i][j] /= a[i][i];
        for (int j = 1; j <= n; ++j) {
            if (j != i && a[j][i]) for (int k = n + 1; k >= i; --k)
                a[j][k] -= a[j][i] * a[i][k];
        }
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%lf", &b[i]);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j) {
            scanf("%lf", &b[n+1]);
            a[i][j] = 2 * (b[n+1] - b[j]);
            a[i][n+1] += b[n+1] * b[n+1] - b[j] * b[j];
        }
    gauss();
    for (int i = 1; i <= n; ++i) printf("%.3lf ", a[i][n+1]);
    return 0;
}
View Code

Lucas定理

#include<iostream>
#include<cstdio>
#define maxn 200001
#define re register
#define int long long
using namespace std;
int inv[maxn],fac[maxn];
int T,x,y,n,m,p;
int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    int r=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return r;
}
inline int c(int n,int m)
{
    if(n<m) return 0;
    return fac[n]*inv[fac[n-m]%p*fac[m]%p]%p;
}
inline int lucas(int n,int m)
{
    if(!n||n==m) return 1;
    return c(n%p,m%p)%p*lucas(n/p,m/p)%p;
}
signed main()
{
    scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&p);
        fac[0]=1;
        fac[1]=inv[1]=1;
        for(re int i=2;i<=max(p,n+m);i++)
        {
            fac[i]=(fac[i-1]*i)%p;
            exgcd(i,p,x,y);
            inv[i]=(x%p+p)%p;
        }
        printf("%lld",lucas(n+m,m)%p),putchar(10);
    }
    return 0;
}
View Code

扩展中国剩余定理

#include <cstdio>

typedef long long LL; const int N = 100002; LL c[N], m[N]; int n;

LL read() {
    LL x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
LL mul(LL a, LL b, LL p) {
    LL res = 0; int f = 1;
    if (a < 0) a = -a, f = -f; if (a >= p) a %= p;
    if (b < 0) b = -b, f = -f; if (b >= p) b %= p;
    for (; b; b >>= 1, a += a + a < p ? a : a - p)
        if ((b & 1) && (res += a) >= p) res -= p;
    return res * f;
}
LL exgcd(LL a, LL b, LL &x, LL &y) {
    if (!b) { x = 1, y = 0; return a; }
    LL t = exgcd(b, a % b, y, x); y -= a / b * x; return t;
}
LL excrt() {
    LL x, y, t;
    for (int i = 2; i <= n; ++i) {
        t = exgcd(m[1], m[i], x, y);
        if ((c[i] - c[1]) % t) return -1;
        m[0] = m[1] / t * m[i], x = mul(x, (c[i] - c[1]) / t, m[0]);
        if ((c[1] += mul(x, m[1], m[0])) >= m[0]) c[1] -= m[0];
        m[1] = m[0];
    }
    if (c[1] < 0) c[1] += m[1]; return c[1];
}
int main() {
    n = read();
    for (int i = 1; i <= n; ++i) m[i] = read(), c[i] = read();
    printf("%lld\n", excrt());
    return 0;
}
View Code

FFT

struct Comp {
    double x, y; Comp() {}
    Comp(double a, double b) : x(a), y(b) {}
    Comp operator + (const Comp &r) { return Comp(x + r.x, y + r.y); }
    Comp operator - (const Comp &r) { return Comp(x - r.x, y - r.y); }
    Comp operator * (const Comp &r) { return Comp(x * r.x - y * r.y, x * r.y + y * r.x); }
} a[N], b[N];

void FFT(Comp *A, int f) {
    for (int i = 0; i < n; ++i) if (i < R[i]) std::swap(A[i], A[R[i]]);
    for (int i = 1; i < n; i <<= 1) {
        Comp wn(cos(PI / i), f * sin(PI / i));
        for (int j = 0, r = i << 1; j < n; j += r) {
            Comp w(1, 0);
            for (int k = 0; k < i; ++k, w = w * wn) {
                Comp x = A[j + k], y = w * A[i + j + k];
                A[j + k] = x + y, A[i + j + k] = x - y;
            }
        }
    }
}
int main() {
    //m为答案的最高次数
    for (n = 1; n <= m; n <<= 1) ++L;
    for (int i = 0; i < n; ++i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    FFT(a, 1), FFT(b, 1);
    for (int i = 0; i < n; ++i) a[i] = a[i] * b[i];
    FFT(a, -1);
    for (int i = 0; i <= m; ++i) printf("%d ", (int)(a[i].x / n + 0.5));
}
View Code

任意模数NTT

#include <cstdio>
#include <algorithm>

typedef long long LL; const int N = 262150;
int a[N], b[N], n, m, nn, mm, pp, R[N], L, p[N], g[N]; LL f[2][N];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
void exgcd(LL a, LL b, LL &x, LL &y) {
    if (!b) { x = 1, y = 0; return; }
    exgcd(b, a % b, y, x), y -= a / b * x;
}
LL ksm(LL a, LL b, LL p) {
    LL res = 1;
    for (; b; b >>= 1, a = 1LL * a * a % p)
        if (b & 1) res = 1LL * res * a % p;
    return res;
}
LL mul(LL a, LL b, LL p) {
    LL res = 0; int f = 1;
    if (a < 0) a = -a, f = -f; if (a >= p) a %= p;
    if (b < 0) b = -b, f = -f; if (b >= p) b %= p;
    for (; b; b >>= 1, a += a + a < p ? a : a - p)
        if ((b & 1) && (res += a) >= p) res -= p;
    return res * f; 
}
void NTT(LL *A, int f, int t) {
    for (int i = 0; i < n; ++i) if (i < R[i]) std::swap(A[i], A[R[i]]);
    for (int i = 1; i < n; i <<= 1) {
        int wn = ksm(f ? 3 : g[t], (p[t] - 1) / (i << 1), p[t]);
        for (int j = 0, r = i << 1; j < n; j += r) {
            int w = 1;
            for (int k = 0; k < i; ++k, w = 1LL * w * wn % p[t]) {
                int x = A[j + k], y = 1LL * w * A[i + j + k] % p[t];
                A[j + k] = (x + y) % p[t], A[i + j + k] = (x - y + p[t]) % p[t];
            }
        }
    }
}
void solve(int t, int k) {
    LL c[N] = {}, d[N] = {};
    for (int i = 0; i <= nn; ++i) c[i] = a[i];
    for (int i = 0; i <= mm; ++i) d[i] = b[i];
    NTT(c, 1, t), NTT(d, 1, t);
    for (int i = 0; i < n; ++i) f[k][i] = 1LL * c[i] * d[i] % p[t];
    NTT(f[k], 0, t);
    int inv = ksm(n, p[t] - 2, p[t]);
    for (int i = 0; i <= m; ++i) f[k][i] = 1LL * f[k][i] * inv % p[t];
}
int main() {
    nn = read(), mm = read(), pp = read();
    for (int i = 0; i <= nn; ++i) a[i] = read();
    for (int i = 0; i <= mm; ++i) b[i] = read();
    m = nn + mm; for (n = 1; n <= m; n <<= 1) ++L;
    for (int i = 0; i < n; ++i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    p[1] = 469762049, p[2] = 998244353, p[3] = 1004535809;
    g[1] = 156587350, g[2] = 332748118, g[3] = 334845270;
    solve(1, 0), solve(2, 1);
    LL mod = 1LL * p[1] * p[2], x, y;
    exgcd(p[1], p[2], x, y), x = (x % mod + mod) % mod;
    for (int i = 0; i <= m; ++i) f[0][i] = (f[0][i] + mul(mul(x, f[1][i] - f[0][i] + mod, mod), p[1], mod)) % mod;
    solve(3, 1);
    LL inv = ksm(mod % p[3], p[3] - 2, p[3]);
    for (int i = 0; i <= m; ++i) printf("%lld ", (mul(((f[1][i] - f[0][i]) % p[3] + p[3]) * inv % p[3], mod, pp) + f[0][i]) % pp);
    return 0;
}
View Code

FWT

void FWT_or(int *a,int opt)
{
    for(int i=1;i<N;i<<=1)
        for(int p=i<<1,j=0;j<N;j+=p)
            for(int k=0;k<i;++k)
                if(opt==1)a[i+j+k]=(a[j+k]+a[i+j+k])%MOD;
                else a[i+j+k]=(a[i+j+k]+MOD-a[j+k])%MOD;
}
void FWT_and(int *a,int opt)
{
    for(int i=1;i<N;i<<=1)
        for(int p=i<<1,j=0;j<N;j+=p)
            for(int k=0;k<i;++k)
                if(opt==1)a[j+k]=(a[j+k]+a[i+j+k])%MOD;
                else a[j+k]=(a[j+k]+MOD-a[i+j+k])%MOD;
}
void FWT_xor(int *a,int opt)
{
    for(int i=1;i<N;i<<=1)
        for(int p=i<<1,j=0;j<N;j+=p)
            for(int k=0;k<i;++k)
            {
                int X=a[j+k],Y=a[i+j+k];
                a[j+k]=(X+Y)%MOD;a[i+j+k]=(X+MOD-Y)%MOD;
                if(opt==-1)a[j+k]=1ll*a[j+k]*inv2%MOD,a[i+j+k]=1ll*a[i+j+k]*inv2%MOD;
            }
}
View Code

点分治

#include <cstdio>

const int N = 10005, K = 10000000;

struct Edge {
    int v, w, nxt;
} e[N<<1];

int siz[N], son[N], dep[N], d[N], head[N], vis[N], num[K+5], tot, root, sum, cnt, n, m;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
int max(int x, int y) {
    return x > y ? x : y;
}
void adde(int u, int v, int w) {
    e[++tot].nxt = head[u];
    head[u] = tot;
    e[tot].v = v, e[tot].w = w;
}
void getroot(int u, int f) {
    siz[u] = 1, son[u] = 0;
    for (int i = head[u]; i; i = e[i].nxt) {
        if (e[i].v == f || vis[e[i].v]) continue;
        getroot(e[i].v, u);
        siz[u] += siz[e[i].v];
        son[u] = max(son[u], siz[e[i].v]);
    }
    son[u] = max(son[u], sum - siz[u]);
    if (son[u] < son[root]) root = u;
}
void getdeep(int u, int f) {
    d[++cnt] = dep[u];
    for (int i = head[u]; i; i = e[i].nxt) {
        if (e[i].v == f || vis[e[i].v]) continue;
        dep[e[i].v] = dep[u] + e[i].w, getdeep(e[i].v, u);
    }
}
void calc(int u, int f, int t) {
    cnt = dep[u] = 0, getdeep(u, u);
    for (int i = 1; i <= cnt; ++i)
        for (int j = 1; j <= cnt; ++j) {
            if (f && d[i] + d[j] <= K) ++num[d[i]+d[j]];
            else if (d[i] + d[j] + t <= K) --num[d[i]+d[j]+t];
        }
}
void solve(int u) {
    calc(u, 1, 0), vis[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt) {
        if (vis[e[i].v]) continue;
        calc(e[i].v, 0, e[i].w << 1);
        sum = siz[e[i].v], son[root=0] = n;
        getroot(e[i].v, 0), solve(root);
    }
}

int main() {
    n = read(), m = read();
    for (int i = 1, u, v, w; i < n; ++i)
        u = read(), v = read(), w = read(), adde(u, v, w), adde(v, u, w);
    son[root=0] = sum = n, getroot(1, 0), solve(root);
    while (m--) puts(num[read()] ? "AYE" : "NAY");
    return 0;
}
View Code

分块

#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
#include <queue>

int n;

struct Point {
    int val, be, pos;
    bool operator < (const int &rhs) const {
        return val < rhs;
    }
    bool operator < (const Point &rhs) const {
        return val < rhs.val;
    } 
} a[1000005];

struct Block {
    int l, r, tag;
} b[1005];

inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (!isdigit(c)) {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (isdigit(c)) {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}

inline void build() {
    int block = sqrt(n), num = (n - 1) / block + 1;
    for (register int i = 1; i <= n; ++ i) {
        a[i].be = (i - 1) / block + 1;
    }
    for (register int  i = 1; i <= num; ++ i) {
        b[i].l = (i - 1) * block + 1, b[i].r = i * block;
        if (i == num) b[i].r = n;
        std::sort(a + b[i].l, a + b[i].r + 1);
    }
}

struct Node {
    int val, pos;
};
std::queue<Node> Q1, Q2;

inline void merge(int cur) {
    int p = b[cur].l;
    while (!Q1.empty() && !Q2.empty()) {
        if (Q1.front().val <= Q2.front().val) {
            a[p].val = Q1.front().val, a[p++].pos = Q1.front().pos;
            Q1.pop();
        } else {
            a[p].val = Q2.front().val, a[p++].pos = Q2.front().pos;
            Q2.pop();
        }
    }
    while (!Q1.empty()) {
        a[p].val = Q1.front().val, a[p++].pos = Q1.front().pos;
        Q1.pop();
    }
    while (!Q2.empty()) {
        a[p].val = Q1.front().val, a[p++].pos = Q1.front().pos;
        Q2.pop();
    }
}

inline void update(int L, int R, int W) {
    if (L != b[a[L].be].l) {
        for (register int i = b[a[L].be].l; i <= b[a[L].be].r; ++ i)
            if (a[i].pos >= L) {
                a[i].val += W;
                Q1.push(Node{a[i].val, a[i].pos});
            } else {
                Q2.push(Node{a[i].val, a[i].pos});
            }
        merge(a[L].be);
        L = b[a[L].be + 1].l;
    }
    if (R != b[a[R].be].r) {
        for (register int i = b[a[R].be].l; i <= b[a[R].be].r; ++ i)
            if (a[i].pos <= R) {
                a[i].val += W;
                Q1.push(Node{a[i].val, a[i].pos});
            } else {
                Q2.push(Node{a[i].val, a[i].pos});
            }
        merge(a[R].be);
        R = b[a[R].be - 1].r;
    }
    for (register int i = a[L].be; i <= a[R].be; ++ i)
            b[i].tag += W;
}

inline int query(int L, int R, int C) {
    int cnt = 0;
    if (L != b[a[L].be].l) {
        for (register int i = b[a[L].be].l; i <= b[a[L].be].r; ++ i)
            if (a[i].pos >= L && a[i].val + b[a[L].be].tag >= C) ++ cnt;
        L = b[a[L].be].l;
    }
    if (R != b[a[R].be].r) {
        for (register int i = b[a[R].be].l; i <= b[a[R].be].r; ++ i)
            if (a[i].pos <= R && a[i].val + b[a[R].be].tag >= C) ++ cnt;
        R = b[a[R].be].r;
    }
    for (register int i = a[L].be; i <= a[R].be; ++ i) {
        int p = std::lower_bound(a + b[i].l, a + b[i].r + 1, C - b[i].tag) - a - b[i - 1].r;
        cnt += b[i].r - b[i].l + 1 - p + 1;
    }
    return cnt;
}

int main() {
    n = read(); int m = read();
    for (register int i = 1; i <= n; ++ i) 
            a[i].val = read(), a[i].pos = i;
    build();
    while (m--) {
        char opt = getchar();
        while (opt != 'A' && opt != 'M') opt = getchar();
        if (opt == 'M') {
            int L = read(), R = read(), W = read();
            update(L, R, W);
        } else {
            int L = read(), R = read(), C = read();
            printf("%d\n", query(L, R, C));
        }
    }
    return 0;
} 
View Code

莫队

#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>

inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (!isdigit(c)) {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (isdigit(c)) {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}

long long gcd(long long x, long long y) {
    return y ? gcd(y, x % y) : x;
}

struct Ask {
    int l, r, id, be;
    bool operator < (const Ask &rhs) const {
        return be ^ rhs.be ? l < rhs.l : be & 1 ? r < rhs.r : r > rhs.r;
    }
} q[50005];

struct Ans {
    long long first, second;
} anslist[50005];

int tub[50005], a[50005];

int main() {
    int n = read(), m = read();
    for (register int i = 1; i <= n; ++ i) {
        a[i] = read();
    }
    int block = n / sqrt(m * 2 / 3);
    for (register int i = 1; i <= m; ++ i) {
        q[i].l = read(), q[i].r = read(), q[i].id = i;
        q[i].be = (q[i].l - 1) / block + 1;
    }
    std::sort(q + 1, q + m + 1);
    int l = q[1].l, r = q[1].l; long long ans = 0; tub[a[l]] = 1;
    for (register int i = 1; i <= m; ++ i) {
        while (l < q[i].l) ans -= --tub[a[l++]];
        while (l > q[i].l) ans += tub[a[--l]]++;
        while (r < q[i].r) ans += tub[a[++r]]++;
        while (r > q[i].r) ans -= --tub[a[r--]];
        anslist[q[i].id].first = ans;
        anslist[q[i].id].second = 1LL*(q[i].r - q[i].l + 1) * (q[i].r - q[i].l) / 2;
    }
    for (register int i = 1; i <= m; ++ i) {
        if (anslist[i].first == 0) puts("0/1");
        else {
            long long div = gcd(anslist[i].first, anslist[i].second);
            printf("%lld/%lld\n", anslist[i].first / div, anslist[i].second / div);
        }
    }
    return 0;
}
View Code

带修莫队

#include <cstdio>
#include <algorithm>
#include <cmath>

const int N = 50005;

int tot, clock, a[N], be[N], buc[1000005], cnt, ans[N];

struct Query {
    int l, r, id, t;
    bool operator < (const Query &cmp) const {
        if (be[l] == be[cmp.l]) {
            if (be[r] == be[cmp.r]) return t < cmp.t;
            return r < cmp.r;
        }
        return l < cmp.l;
    }
} q[N];

struct Change {
    int x, y;
} c[N];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
void swap(int &x, int &y) {
    x ^= y, y ^= x, x ^= y;
}
void change(int t, int i) {
    if (q[i].l <= c[t].x && c[t].x <= q[i].r) {
        if (--buc[a[c[t].x]] == 0) --cnt;
        if (buc[c[t].y]++ == 0) ++cnt;
    }
    swap(a[c[t].x], c[t].y);
}

int main() {
    int n = read(), m = read(), sz = pow(n, 2.0 / 3);
    for (int i = 1; i <= n; ++i)
        a[i] = read(), be[i] = (i - 1) / sz + 1;
    for (int i = 1; i <= m; ++i) {
        char opt = getchar();
        while (opt != 'Q' && opt != 'R') opt = getchar();
        int l = read(), r = read();
        if (opt == 'Q') q[++tot] = (Query){l, r, tot, clock};
        else c[++clock] = (Change){l, r};
    }
    std::sort(q + 1, q + tot + 1);
    int l = 1, r = 0, t = 0;
    for (int i = 1; i <= tot; ++i) {
        while (l < q[i].l) if (--buc[a[l++]] == 0) --cnt;
        while (l > q[i].l) if (buc[a[--l]]++ == 0) ++cnt;
        while (r > q[i].r) if (--buc[a[r--]] == 0) --cnt;
        while (r < q[i].r) if (buc[a[++r]]++ == 0) ++cnt;
        while (t < q[i].t) change(++t, i);
        while (t > q[i].t) change(t--, i);
        ans[q[i].id] = cnt;
    }
    for (int i = 1; i <= tot; ++i) printf("%d\n", ans[i]);
    return 0;
}
View Code

CDQ分治

#include <cstdio>
#include <algorithm>

const int N = 100005;

struct Node {
    int a, b, c, n, v;
    bool operator < (const Node &rhs) const {
        return a == rhs.a ? (b == rhs.b ? c < rhs.c : b < rhs.b) : a < rhs.a;
    }
} a[N], b[N];
int n, k, ans[N], sum[N<<1];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
void update(int x, int y) {
    while (x <= k) sum[x] += y, x += x & (-x);
}
int query(int x) {
    int res = 0;
    while (x) res += sum[x], x -= x & (-x);
    return res;
}
void clear(int x) {
    while (x <= k) {
        if (sum[x]) sum[x] = 0, x += x & (-x);
        else break;
    }
}
void cdq(int l, int r) {
    if (l >= r) return;
    int mid = (l + r) >> 1, p = l, q = mid + 1, t = 0;
    cdq(l, mid), cdq(mid + 1, r);
    while (p <= mid && q <= r) {
        if (a[p].b <= a[q].b) update(a[p].c, a[p].n), b[t++] = a[p++];
        else a[q].v += query(a[q].c), b[t++] = a[q++];
    }
    if (p <= mid) {
        for (int i = l; i < p; ++i) clear(a[i].c);
        while (p <= mid) b[t++] = a[p++];
    } else if (q <= r) {
        while (q <= r) a[q].v += query(a[q].c), b[t++] = a[q++];
        for (int i = l; i <= mid; ++i) clear(a[i].c);
    }
    for (int i = 0; i < t; ++i) a[l+i] = b[i];
}
int main() {
    n = read(), k = read();
    for (int i = 1; i <= n; ++i)
        a[i].a = read(), a[i].b = read(), a[i].c = read(), a[i].n = 1;
    std::sort(a + 1, a + n + 1);
    int cnt = 1;
    for (int i = 2; i <= n; ++i) {
        if (a[i].a != a[i-1].a || a[i].b != a[i-1].b || a[i].c != a[i-1].c) a[++cnt] = a[i];
        else ++a[cnt].n;
    }
    cdq(1, cnt);
    for (int i = 1; i <= cnt; ++i) ans[a[i].v+a[i].n-1] += a[i].n;
    for (int i = 0; i < n; ++i) printf("%d\n", ans[i]);
    return 0;
}
View Code

BSGS

https://www.cnblogs.com/fly-in-milkyway/p/10322617.html

https://www.cnblogs.com/fly-in-milkyway/p/10322542.html

欧拉回路

#include <cstdio>

const int N = 100005, M = 200005;
int head[N], nxt[M<<1], pnt[M<<1], tot = 1, in[N], out[N], vis[M], ans[M], cnt;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
void add_edge(int u, int v) {
    nxt[++tot] = head[u];
    head[u] = tot, pnt[tot] = v;
}
void dfs(int cur) {
    for (int &i = head[cur], j; i; i = nxt[i]) { //当前弧优化
        if (vis[(j=i)>>1]) continue;
        vis[j>>1] = 1, dfs(pnt[j]), ans[++cnt] = j; //注意要先递归, 再计入答案
    }
}

int main() {
    int t = read(), n = read(), m = read();
    for (int i = 1; i <= m; ++i) {
        int u = read(), v = read();
        add_edge(u, v);
        if (t == 2) ++out[u], ++in[v], ++tot;
        else add_edge(v, u), ++in[u], ++in[v];
    }
    if (t == 1) {
        for (int i = 1; i <= n; ++i)
            if (in[i] & 1) { puts("NO"); return 0; }
    } else {
        for (int i = 1; i <= n; ++i)
            if (in[i] != out[i]) { puts("NO"); return 0; }
    }
    dfs(pnt[2]); //选择一个标号存在的点
    if (cnt < m) puts("NO");
    else {
        puts("YES");
        for (int i = cnt; i; --i) //由于递归时是倒着计入的, 因此要逆序输出
            printf("%d ", (ans[i] >> 1) * (ans[i] & 1 ? -1 : 1));
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/fly-in-milkyway/p/10625570.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值