大大大大板子
枚举子集
for (int x = s; x; x = (x - 1) & s) {}
高维前缀和
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)];
线性基
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]; }
线性求逆元
inv[1] = 1; for (int i = 2; i <= n; ++i) inv[i] = 1LL * (p - p / i) * inv[p % i] % p;
欧拉筛
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]; } } }
文艺平衡树
#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; }
主席树
#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; }
二维线段树
#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; }
二逼平衡树
#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; }
树状数组套主席树
#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; }
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; }
线段树合并
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; }
单调队列优化多重背包
设 $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; }
树上背包优化
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; }
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; } }
割点
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; }
点双
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]); } }
边双
圆方树
虚树
#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; }
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; }
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; }
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; }
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; }
后缀数组
#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; }
后缀自动机
#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; }
回文自动机
#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; }
最小表示法
#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; }
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; }
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; }
高斯消元
#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; }
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; }
扩展中国剩余定理
#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; }
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)); }
任意模数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; }
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; } }
点分治
#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; }
分块
#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; }
莫队
#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; }
带修莫队
#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; }
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; }
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; }