板子
如果什么都记,必然很难找。
所以大型数据结构就不记了。
快读 & 快写
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 * 10 + c - '0', c = getchar();
return x * f;
}
void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
重载不完全的矩阵
#include <initializer_list>
struct matrix {
int n, m; std::vector<std::vector<int>> a;
matrix() {}
matrix(int n, int m) : n(n), m(m) {
a.assign(n, std::vector<int>(m));
}
matrix(int n) : n(n), m(m) {
a.assign(n, std::vector<int>(m));
for (int i = 0; i < n; i++) a[i][i] = 1;
}
auto operator [] (int i) {
return a[i];
}
matrix operator * (const matrix &tmp) {
assert(m == tmp.n);
matrix t(n, tmp.m);
for (int i = 0; i < n; i++)
for (int j = 0; j < tmp.m; j++)
for (int k = 0; k < m; k++)
t[i][j] = (t[i][j] + 1ll * a[i][k] * tmp.a[k][j] % mod) % mod;
return t;
}
matrix operator ^ (int tmp) const {
assert(n == m);
matrix ans(n), t = *this;
for (; tmp; tmp >>= 1) {
if(tmp & 1) ans = ans * t;
t = t * t;
}
return ans;
}
matrix operator + (const matrix &tmp) const {
assert(n == tmp.n && m == tmp.m);
matrix ans = *this;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
ans[i][j] = add(a[i][j], tmp.a[i][j]);
return ans;
}
void print(string s) {
cout << s << ":\n";
// printf("n=%d m=%d\n", n, m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
printf("%d ", a[i][j]);
} printf("\n");
} printf("\n");
}
bool operator == (const matrix &tmp) const {
assert(n == tmp.n && m == tmp.m);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) if(a[i][j] != tmp.a[i][j]) return 0;
return 1;
}
};
inv
int invn[M];
void pre(int n) {
invn[1] = 1;
for (int i = 2; i <= n; i++)
invn[i] = 1ll * (p - p/i) * invn[p%i] %p;
}
void exgcd(int a, int b, int &x, int &y) {
if (!b) return x = 1, y = 0, void();
exgcd(b, a % b, y, x), y -= a / b * x;
}
int inv(int x, int p) { return exgcd(x, p, x, *new int), (x % p + p) % p; }
\(\varphi(n)\)
int phi(int n) {
int ans = n;
for (int i = 2; i * i <= n; i++) if(n % i == 0) {
ans = ans / i * (i-1); while (n % i == 0) n /= i;
}
if(n > 1) ans = ans / n * (n-1);
return ans;
}
淀粉树
#include <bits/stdc++.h>
using LL = long long;
std::vector<std::vector<int>> e;
std::vector<int> mx, siz, vis, fa;
struct BIT {
std::vector<int> s;
int n;
#define lowbit(x) ((x) & (-(x)))
BIT(int n = -1) : n(n), s(n + 1) {}
void mdf(int x, int t) {
++x;
for (; x <= n; x += lowbit(x))
s[x] += t;
}
int qry(int x) {
++x; int ans(0);
x = std::min(x, n);
if (x < 0) return 0;
for (; x; x -= lowbit(x))
ans += s[x];
return ans;
}
};
std::vector<BIT> s0, s1;
int main() {
int n, m; scanf("%d %d", &n, &m);
e.resize(n);
std::vector<int> a(n);
for (int &x : a) scanf("%d", &x);
for (int i = 1, a, b; i < n; i++) {
scanf("%d %d", &a, &b), --a, --b;
e[a].push_back(b), e[b].push_back(a);
}
std::vector<int> dfn(n), dep(n);
int k = std::log2(n - 1) + 1;
std::vector<std::vector<int>> mi(k, std::vector<int>(n));
auto mn = [&](int x, int y) {
if (x == -1 || y == -1) return -1;
return dep[x] < dep[y] ? x : y;
};
{
int dfc = 0;
std::function<void(int, int)> dfs = [&](int u, int f) {
assert(u < n && u >= 0);
mi[0][dfn[u] = dfc++] = f;
for (int v : e[u]) if (v != f)
dep[v] = dep[u] + 1, dfs(v, u);
};
dfs(0, -1);
for (int i = 1; i < k; i++)
for (int j = 0; j + (1 << i) - 1 < n; j++)
mi[i][j] = mn(mi[i - 1][j], mi[i - 1][j + (1 << i - 1)]);
}
auto lca = [&](int u, int v) {
if (u == v) return u;
if ((u = dfn[u]) > (v = dfn[v])) std::swap(u, v);
int x = std::log2(v - u++);
return mn(mi[x][u], mi[x][v - (1 << x) + 1]);
};
auto dis = [&](int u, int v) {
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
};
fa = mx = siz = vis = std::vector<int>(n);
std::vector<std::vector<int>> ch(n);
s0.resize(n), s1.resize(n);
fa.assign(n, -1);
{
auto getrt = [&](int x) -> int {
int rt = -1, tot = siz[x];
std::function<void(int, int)> dfs = [&](int u, int f) {
mx[u] = 0, siz[u] = 1;
for (int v : e[u]) if (!vis[v] && v != f)
dfs(v, u), siz[u] += siz[v], mx[u] = std::max(mx[u], siz[v]);
mx[u] = std::max(mx[u], tot - siz[u]);
if (rt == -1 || mx[u] < mx[rt]) rt = u;
};
return dfs(x, -1), rt;
};
std::function<void(int)> dfs = [&](int u) {
// printf("dfs %d fa %d\n", u, fa[u]);
vis[u] = 1;
std::function<void(int, int)> calc = [&](int x, int f) {
// printf("calc %d %d\n", x, u);
siz[x] = 1;
s0[u].mdf(dis(u, x), a[x]);
// printf("upd0 %d %d %d\n", u, dis(u, x), a[x]);
if (fa[u] != -1) s1[u].mdf(dis(x, fa[u]), a[x]); //, printf("upd1 %d %d %d\n", u, dis(x, fa[u]), a[x]);
for (int y : e[x]) if (!vis[y] && y != f)
calc(y, x), siz[x] += siz[y];
};
calc(u, -1);
for (int v : e[u]) if (!vis[v]) {
int x = getrt(v);
fa[x] = u, ch[u].push_back(x);
s0[x] = BIT(siz[v] + 1);
s1[x] = BIT(siz[v] + dis(x, u) + 1);
// printf("link %d %d\n", u, x);
dfs(x);
}
};
siz[0] = n;
fa.assign(n, -1);
int rt = getrt(0);
s0[rt] = s1[rt] = BIT(n + 1);
dfs(rt);
}
int lst = 0;
while (m--) {
int op, x, y; scanf("%d %d %d", &op, &x, &y);
x ^= lst, y ^= lst;
--x;
if (op == 0) {
int ans = 0;
for (int u = x; u != -1; u = fa[u]) {
ans += s0[u].qry(y - dis(x, u));
if (fa[u] != -1) ans -= s1[u].qry(y - dis(x, fa[u]));
}
printf("%d\n", lst = ans);
} else {
for (int u = x; u != -1; u = fa[u]) {
s0[u].mdf(dis(u, x), y - a[x]);
if (fa[u] != -1) s1[u].mdf(dis(fa[u], x), y - a[x]);
}
a[x] = y;
}
}
}
mod
int qpow(int a, int b) {
long long ans = 1ll;
for (; b; b >>= 1) {if(b & 1) ans = 1ll * ans * a % mod; a = 1ll * a * a % mod;}
return ans;
}
int inv(int k) {return qpow(k, mod - 2);}
int add(int a, int b) {a += b; return a > mod ? a-mod : a;}
int del(int a, int b) {a -= b; return a < 0 ? a+mod : a;}
void addn(int &x, int y) {x += y; if(x > mod) x -= mod;}
int fact(int x) {int ans = 1; for (int i = 1; i <= x; i++) ans = 1ll * ans * i % mod; return ans;}
int fac[M], invfac[M], invn[M];
void pre(int n = 250000) {
fac[0] = invfac[0] = fac[1] = invfac[1] = invn[1] = 1;
for (int i = 2; i <= n; i++)
invn[i] = 1ll * (mod - mod/i) * invn[mod%i] % mod,
fac[i] = 1ll * fac[i-1] * i % mod,
invfac[i] = 1ll * invfac[i-1] * invn[i] % mod;
}
int C(int n, int m) {return m > n ? 0 : 1ll * fac[n] * invfac[m] % mod * invfac[n-m] % mod;}
Mint
(来源 https://www.cnblogs.com/Rainbowsjy/p/13907092.html)
const int mod = 998244353;
struct modint {
int x;
modint(int o = 0) {x = o;}
modint &operator = (int o) {return x = o, *this;}
modint &operator += (modint o) {return x = x+o.x >= mod ? x+o.x-mod : x+o.x, *this;}
modint &operator -= (modint o) {return x = x-o.x < 0 ? x-o.x+mod : x-o.x, *this;}
modint &operator *= (modint o) {return x = 1ll*x*o.x%mod, *this;}
modint &operator ^= (int b) {
modint a = *this, c = 1;
for (; b; b >>= 1, a *= a) if(b & 1) c *= a;
return x=c.x, *this;
}
modint &operator /= (modint o) {return *this *= o ^= mod-2;}
friend modint operator + (modint a, modint b) {return a += b;}
friend modint operator - (modint a, modint b) {return a -= b;}
friend modint operator * (modint a, modint b) {return a *= b;}
friend modint operator / (modint a, modint b) {return a /= b;}
friend modint operator ^(modint a,int b) {return a ^= b;}
friend bool operator == (modint a, int b) {return a.x == b;}
friend bool operator != (modint a, int b) {return a.x != b;}
bool operator ! () {return !x;}
modint operator - () {return x ? mod-x : 0;}
bool operator < (const modint &b) const {return x < b.x;}
};
inline modint qpow(modint x, int y) {return x ^ y;}
std::vector<modint> fac, ifac, iv;
inline void initC(int n) {
if(iv.empty()) fac = ifac = iv = std::vector<modint>(2,1);
int m = iv.size(); ++n;
if(m >= n) return;
iv.resize(n + 1), fac.resize(n + 1), ifac.resize(n + 1);
for (int i = m; i <= n; i++) {
iv[i] = iv[mod%i] * (mod - mod/i);
fac[i] = fac[i-1] * i, ifac[i] = ifac[i-1] * iv[i];
}
}
inline modint C(int n, int m) {
if(m<0 || n<m) return 0;
return initC(n), fac[n] * ifac[m] * ifac[n-m];
}
并查集
int find(int u) {return fa[u] == u ? u : fa[u] = find(fa[u]);}
void merge(int u, int v) {
u = find(u); v = find(v); if(u != v) fa[u] = v;
}
可撤销并查集
struct mdf {
int x, y, dh;
};
struct dsu {
int fa[N], h[N], siz[N];
int find(int x) {return fa[x] == x ? x : find(fa[x]);}
mdf q[N]; int top;
void merge(int x, int y) {
if((x = find(x)) != (y = find(y))) {
if(h[x] <= h[y]) swap(x, y);
siz[x] += siz[y]; fa[y] = x; h[x] += h[x] == h[y];
q[++top] = {x, y, h[x] == h[y]};
}
}
void roll(int x) {
while (top > x) {
int x = q[top].x, y = q[top].y, dh = q[top].dh;
siz[x] -= siz[y]; fa[y] = y; h[x] -= dh; --top;
}
}
}t;
数论函数筛子
int mu[M], p[M], tt, phi[M], low[M], invn[M], invphi[M]; bool np[M];
void pre(int n){
phi[1] = mu[1] = 1; low[1] = 1; invn[1] = 1;
for(int i = 2; i <= n; i++) {
invn[i] = 1ll * (mod - mod/i) * invn[mod % i] % mod;
if(!np[i]) p[++tt] = i, mu[i] = -1, phi[i] = i-1, low[i] = i;
for(int j = 1; j <= tt; j++) {
int k = p[j] * i; if(k > n) break;
if(i % p[j] == 0) {
np[k] = 1; mu[k] = 0; phi[k] = phi[i] * p[j];
low[k] = low[i] * p[j];
break;
}
np[k] = 1; mu[k] = -mu[i]; phi[k] = phi[i] * (p[j]-1); low[k] = p[j];
}
}
}
\(\mu\) and \(\varphi\)
int mu[M], p[M], tt, phi[M]; bool f[M]; LL summu[M], sumphi[M];
void pre(int n) {
sumphi[1] = summu[1] = f[1] = mu[1] = 1;
for (int i = 2; i <= n; i++) {
if(!f[i]) p[++tt] = i, mu[i] = -1, phi[i] = i-1;
for (int j = 1; j <= tt; j++) {
int k = p[j] * i; if(k > n) break;
if(i % p[j] == 0) {f[k] = 1; mu[k] = 0; phi[k] = phi[i] * p[j]; break;}
f[k] = 1; mu[k] = -mu[i]; phi[k] = phi[i] * (p[j]-1);
}
summu[i] = summu[i-1] + 1ll * mu[i]; sumphi[i] = sumphi[i-1] + 1ll * phi[i];
}
}
dij
struct node {
int dis, i;
bool operator < (const node &tmp) const {
return dis > tmp.dis;
}
}d[M];
bool vis[M]; priority_queue<node> q;
void dij(int t) {
for (int i = 1; i <= n; i++) d[i].dis = inf, d[i].i = i;
d[t].dis = 0; q.push(d[t]);
while (!q.empty()) {
int u = q.top().i; q.pop();
if(vis[u]) continue; vis[u] = 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(d[v].dis > d[u].dis + e[i].w) {
d[v].dis = d[u].dis + e[i].w;
q.push(d[v]);
}
}
}
}
膜数非质数的组合数
struct num {
num() {x = 0; memset(md, 0, sizeof(md));}
num(int k) {
memset(md, 0, sizeof(md)); if(k == 0) return;
for (int i = 1; i <= cnt; i++) {
while (k % p[i] == 0) k /= p[i], ++md[i];
}
x = k; invx = inv(k);
}
num operator / (const num &t) const{
num ans; ans.x = 1ll * x * t.invx % mod, ans.invx = 1ll * invx * t.x % mod;
for (int i = 1; i <= cnt; i++) ans.md[i] = md[i] - t.md[i];
return ans;
}
num operator * (const num &t) const{
num ans; ans.x = 1ll * x * t.x % mod, ans.invx = 1ll * invx * t.invx % mod;
for (int i = 1; i <= cnt; i++) ans.md[i] = md[i] + t.md[i];
return ans;
}
int to_num() {
int ans = x;
for (int i = 1; i <= cnt; i++) ans = 1ll * ans * qpow(p[i], md[i]) % mod;
return ans;
}
int x, invx; short md[N];
} s[M];
int C(int n, int m) {
if(m > n || m < 0) return 0;
return (s[n] / s[m] / s[n-m]).to_num();
}
void pre() {
int t = mod;
for (int i = 2; i * i <= t; i++)
if(t % i == 0) {p[++cnt] = i; while (t % i == 0) t /= i;}
if(t > 1) p[++cnt] = t;
phimod = phi(mod);
s[0] = num(1);
for (int i = 1; i <= n; i++) s[i] = s[i-1] * num(i);
}
一棵可爱的可持久化 Trie
#define D 30
struct Trie {
int rt[M], son[M][2], cnt[M], cnt1;
inline int build() {return ++cnt1;}
void ins(int &p, int q, int k, int dep) {
if(dep == -2) return;
cnt[p = build()] = cnt[q] + 1; son[p][0] = son[q][0]; son[p][1] = son[q][1];
ins(son[p][(k >> dep) & 1], son[q][(k >> dep) & 1], k, dep-1);
}
int query(int l, int r, int k, int dep) {
int val = (k >> dep) & 1;
if(dep == -1) return 0;
if(cnt[son[r][val ^ 1]] - cnt[son[l][val ^ 1]]) return (1 << dep) | query(son[l][val^1], son[r][val^1], k, dep-1);
return query(son[l][val], son[r][val], k, dep-1);
}
void debug(int l, int r, int dep) {
if(dep == -1) return;
printf("now l=%d r=%d dep=%d cnt=%d\n", l, r, dep, cnt[r] - cnt[l]);
if(cnt[son[r][0]] - cnt[son[l][0]]) printf("to l\n"), debug(son[l][0], son[r][0], dep-1);
if(cnt[son[r][1]] - cnt[son[l][1]]) printf("to r\n"), debug(son[l][1], son[r][1], dep-1);
printf("end l=%d r=%d dep=%d\n", l, r, dep);
}
} s1, s2;
倍增 LCA
struct LCA {
int f[M][35], d[M];
LCA() {memset(f, 0, sizeof(f)); memset(d, 0, sizeof(d));}
void dfs(int u, int fa) {
f[u][0] = fa; d[u] = d[fa] + 1;
for (int i = 1; i <= 30; i++) f[u][i] = f[f[u][i - 1]][i - 1];
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to; if(v == fa) continue; dfs(v, u);
}
}
int lca(int u, int v) {
if (d[u] < d[v]) swap(u, v);
for (int i = 30; i >= 0; i--) if(d[f[u][i]] >= d[v]) u = f[u][i];
if (u == v) return u;
for (int i = 30; i >= 0; i--) if(f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
return u == v ? u : f[u][0];
}
}t;
Splay
struct Splay {
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define pos(x) (ch[fa[x]][1] == x)
int ch[M][2], val[M], cnt[M], cnt1, siz[M], fa[M], rt;
void pushup(int x) {siz[x] = siz[ls(x)] + siz[rs(x)] + cnt[x];}
void clear(int x) {ch[x][0] = ch[x][1] = fa[x] = val[x] = siz[x] = cnt[x] = 0;}
int build(int t) {++cnt1; cnt[cnt1] = siz[cnt1] = 1; val[cnt1] = t; return cnt1;}
void rotate(int x) {
int y = fa[x], z = fa[fa[x]], p = pos(x), p2 = pos(y);
ch[y][p] = ch[x][p^1]; if(ch[x][p^1]) fa[ch[x][p^1]] = y;
fa[y] = x; ch[x][p^1] = y; fa[x] = z;
if(z) ch[z][p2] = x;
pushup(y); pushup(x);
}
void splay(int x) {
for (int f = fa[x]; f = fa[x], f; rotate(x)) {
if(fa[f]) rotate(pos(x) == pos(f) ? f : x);
}
rt = x;
}
void insert(int t) {
if(!rt) return rt = build(t), void();
int x = rt, y = 0;
while (1) {
if(val[x] == t) return ++cnt[x], pushup(x), pushup(y), splay(x), void();
y = x; x = ch[x][val[x] < t];
if(!x) {
x = ch[y][val[y] < t] = build(t);
fa[x] = y; pushup(x); pushup(y); splay(x); return;
}
}
}
int kth(int k) {
int x = rt;
while (1) {
if(k <= siz[ls(x)]) {x = ls(x); continue;}
k -= siz[ls(x)];
if(k <= cnt[x]) return splay(x), val[x];
k -= cnt[x]; x = rs(x);
}
}
int rnk(int k) {
int x = rt, ans = 0;
while (1) {
if(val[x] > k) {x = ls(x); continue;}
ans += siz[ls(x)];
if(k == val[x]) return splay(x), ans+1;
ans += cnt[x]; x = rs(x);
}
}
int pre() {
int x = ls(rt);
while (rs(x)) x = rs(x);
return splay(x), x;
}
int nxt() {
int x = rs(rt);
while (ls(x)) x = ls(x);
return splay(x), x;
}
void del(int k) {
rnk(k);
if(cnt[rt] > 1) return --cnt[rt], pushup(rt), void();
if(!ls(rt) && !rs(rt)) return clear(rt), rt = 0, void();
if(!ls(rt)) {int r = rt; rt = rs(rt); fa[rt] = 0; clear(r); return;}
if(!rs(rt)) {int r = rt; rt = ls(rt); fa[rt] = 0; clear(r); return;}
int r = rt; pre(); ch[rt][1] = rs(r); fa[rs(r)] = rt; clear(r); pushup(rt); return;
}
int pre(int k) {insert(k); int ans = val[pre()]; del(k); return ans;}
int nxt(int k) {insert(k); int ans = val[nxt()]; del(k); return ans;}
} tr;
经封装的线段树 & 树剖板子
int w[M], fa[M], dep[M], siz[M], son[M], top[M], dfn[M], rnk[M], out[M], cnt;
void dfs1(int u, int f) {
fa[u] = f; siz[u] = 1; son[u] = -1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to; if(v == f) continue;
dep[v] = dep[u] + 1; dfs1(v, u); siz[u] += siz[v];
if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int f, int t) {
dfn[u] = ++cnt; rnk[cnt] = u; top[u] = t;
if(son[u] != -1) dfs2(son[u], u, t);
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to; if(v == f || v == son[u]) continue;
dfs2(v, u, v);
} out[u] = cnt;
}
int n, m, r, u, v, x, y, z, op; long long p;
struct sg{
int s[M << 2], laz[M << 2];
void pushdown(int o, int l, int r) {
int mid = l + r >> 1;
s[o<<1] = (s[o<<1] + (mid-l+1) * laz[o] % p) % p; laz[o<<1] = (laz[o<<1] + laz[o]) % p;
s[o<<1|1] = (s[o<<1|1] + (r-mid) * laz[o] % p) % p; laz[o<<1|1] = (laz[o<<1|1] + laz[o]) % p;
laz[o] = 0;
}
void build(int o, int l, int r) {
if(l == r) {s[o] = w[rnk[l]]; return;}
int mid = l + r >> 1;
build(o<<1, l, mid); build(o<<1|1, mid+1, r);
s[o] = (s[o<<1] + s[o<<1|1]) % p;
}
void modify(int o, int l, int r, int x, int y, int t) {
if(x <= l && r <= y) {s[o] = (s[o] + (r-l+1) * t % p) % p; laz[o] = (laz[o] + t) % p; return;}
int mid = l + r >> 1; pushdown(o, l, r);
if(x <= mid) modify(o<<1, l, mid, x, y, t);
if(y > mid) modify(o<<1|1, mid+1, r, x, y, t);
s[o] = (s[o<<1] + s[o<<1|1]) % p;
}
int query(int o, int l, int r, int x, int y) {
if(x <= l && r <= y) return s[o];
int mid = l + r >> 1, ans = 0; pushdown(o, l, r);
if(x <= mid) ans = (ans + query(o<<1, l, mid, x, y)) % p;
if(y > mid) ans = (ans + query(o<<1|1, mid+1, r, x, y)) % p;
return ans;
}
void debug(int o, int l, int r) {
printf("%d: l = %d r = %d s = %d\n", o, l, r, s[o]);
if(l == r) return;
int mid = l + r >> 1;
debug(o<<1, l, mid); debug(o<<1|1, mid+1, r);
}
}s;
void add(int x, int y, int z) {
int tx = top[x], ty = top[y];
while (tx != ty) {
if(dep[tx] > dep[ty]) s.modify(1, 1, n, dfn[tx], dfn[x], z), x = fa[tx];
else s.modify(1, 1, n, dfn[ty], dfn[y], z), y = fa[ty];
tx = top[x]; ty = top[y];
}
s.modify(1, 1, n, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]), z); return;
}
int query(int x, int y) {
int tx = top[x], ty = top[y], ans = 0;
while (tx != ty) {
if(dep[tx] > dep[ty]) ans = (ans + s.query(1, 1, n, dfn[tx], dfn[x])) % p, x = fa[tx];
else ans = (ans + s.query(1, 1, n, dfn[ty], dfn[y])) % p, y = fa[ty];
tx = top[x]; ty = top[y];
}
ans = (ans + s.query(1, 1, n, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]))) % p; return ans;
}
sa(不确定正确性)
struct sa {
int sa[M], rk[M << 1], cnt[M], id[M], prerk[M << 1], h[M], val[M << 1], n; char s[M];
void init(char *l) {
n = 1; s[1] = l[0];
for (; l[n-1] != '\0'; n++) s[n] = l[n-1];
--n;
}
bool cmp(int i, int j, int t) {return prerk[sa[j]] == prerk[sa[i]] && prerk[sa[j]+t] == prerk[sa[i]+t];}
void get_sa() {
int m = std::max(256, n), p = 256;
for (int i = 1; i <= n; i++) ++cnt[rk[i] = s[i]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = n; i; i--) sa[cnt[rk[i]]--] = i;
for (int i = 0; (1 << i) <= n; i++) {
int t = (1 << i), k = 0; m = p; //printf("%d\n", m);
for (int j = n; j > n - t; j--) id[++k] = j;
for (int j = 1; j <= n; ++j)
if (sa[j] > t) id[++k] = sa[j] - t;
memset(cnt, 0, sizeof(cnt));
for (int j = 1; j <= n; j++) ++cnt[val[j] = rk[id[j]]];
for (int j = 1; j <= m; j++) cnt[j] += cnt[j-1];
for (int j = n; j; j--) sa[cnt[val[j]]--] = id[j];
memcpy(prerk, rk, sizeof(rk)); p = 0;
for (int j = 1; j <= n; j++) {
if(cmp(j, j-1, t)) rk[sa[j]] = p;
else rk[sa[j]] = ++p;
}
if (p == n) break;
}
for (int i = 1, k = 0; i <= n; i++) {
if (k) --k;
while (s[i+k] == s[sa[rk[i]-1] + k]) ++k;
h[rk[i]] = i;
}
}
bool find(char *str) {
int l = 1, r = n, ans = 0;
while (l <= r) {
int mid = l + r >> 1, val = strcmp(str, &s[sa[mid]]);
if (val == 0) return 1;
else if (val == -1) r = mid - 1, ans = mid;
else l = mid + 1;
}
int m = strlen(str), pl = sa[ans];
for (int i = 1; i <= m; i++) if(str[i-1] != s[pl+i]) return 0;
return 1;
}
} s;
轻微封装的 dinic
struct wll {
int S, T;
struct edge {
int to, nxt, w;
}e[M << 1];
int head[M], cnt1 = 1;
void link(int u, int v, int w) {
e[++cnt1] = {v, head[u], w}; head[u] = cnt1;
e[++cnt1] = {u, head[v], w}; head[v] = cnt1;
}
queue<int> q; int cur[M], n, m, d[M];
bool bfs() {
while (q.size()) q.pop();
q.push(S);
for (int i = 1; i <= n; i++) cur[i] = head[i], d[i] = 0;
d[S] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(e[i].w && !d[v]) {
d[v] = d[u] + 1; q.push(v);
if(v == T) return 1;
}
}
} return 0;
}
int dinic(int u, int flow) {
if(u == T) return flow;
int ret = flow, i;
for (i = cur[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(e[i].w && d[v] == d[u]+1) {
int t = dinic(v, min(ret, e[i].w));
if(!t) d[v] = 0;
e[i].w -= t; e[i^1].w += t;
ret -= t;
if(!ret) return flow;
}
}
cur[u] = i;
return flow - ret;
}
int work() {
int ans = 0;
while (bfs()) ans += dinic(S, inf);
return ans;
}
};
二维压一维+拆点
#define in(a, b) (((a)-1) * c + (b))
#define out(a, b) (in((a), (b)) + r*c)
void print(int u) {
if(u == S) printf("S");
else if(u == T) printf("T");
else printf("(%d,%d,%d)", ((u-1)/c) % r + 1, (u-1)%c+1, u>r*c);
}
poly
反正某道题的提交记录有。
分块
分块基操:查询时需要整块内部贡献、散块对整块、整块对整块。分别处理。
然后有了一种分块:处理 \(pre_{i,j}, nxt_{i,j}\) 分别表示 \(j\) 到第 \(i\) 块块头(\(pos_j \geq i\))与 \(j\) 到第 \(i\) 块块尾(\(pos_j \leq i\))内部的贡献。附加条件是快速处理散块对散块的贡献。
流程:
- 处理 \(pos_j=i\) 的部分。这块可以暴力统计贡献,\(O(n \sqrt n)\)。
- \(pre_{i,j} = pre_{i, j-1} + pre_{i+1, j} + ans(i, j)\),其中 \(ans_{i,j}\) 是 \(i\) 整块对 \(j\) 的答案。这里的 \(+\) 意为结合。
\(ans_{i, j}\) 采取整块式的处理,即统一为所有同块的 \(j\) 求出答案。
看一下这样做的性质。
首先它是在区间选点对。暴力统计 \(pos_j=i\) 的一部分需要这个来只枚举一对点。
然后至少一个区间对一个区间的贡献要好求些。这道题用了双指针,均摊 \(O(1)\)。
一个区间对一个区间很多时候好处在于能按另一个维度的信息排序。这题就是按数值大小排序。
最后信息要好结合。\(\min, +\) 都是好结合的信息。
这里处理的是区间一维最近点对。
void cmin(int &x, int y) { x = min(x, y); }
int n, m, a[M];
pair<int, int> b[M];
int len, block, L[N], R[N], pos[M];
int pre[N][M],
nxt[N][M]; // j 到 i 块首(pos_j <= i)、j 到 i 块头(pos_j >= i)
int ans[M];
void calc(int p, int q) { // q 块所有点对 p 块算 ans
int pos = L[p];
for (int i = L[q]; i <= R[q]; i++) {
int x = b[i].first;
while (pos < R[p] && b[pos + 1].first <= x) ++pos;
int y = b[pos].first, z = pos + 1 == R[p] + 1 ? 2e9 : b[pos + 1].first;
ans[b[i].second] = min(abs(x - y), abs(x - z));
}
}
void init() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = {a[i], i};
len = sqrt(n);
block = (n - 1) / len + 1;
for (int i = 1; i <= block; i++) {
L[i] = R[i - 1] + 1, R[i] = min(i * len, n);
for (int j = L[i]; j <= R[i]; j++) pos[j] = i;
}
for (int i = 1; i <= block; i++) {
sort(b + L[i], b + R[i] + 1);
pre[i][L[i]] = 2e9;
for (int j = L[i] + 1; j <= R[i]; j++) {
int mn = 2e9;
for (int k = L[i]; k < j; k++) cmin(mn, abs(a[j] - a[k]));
pre[i][j] = min(pre[i][j - 1], mn);
}
nxt[i][R[i]] = 2e9;
for (int j = R[i] - 1; j >= L[i]; j--) {
int mn = 2e9;
for (int k = R[i]; k > j; k--) cmin(mn, abs(a[j] - a[k]));
nxt[i][j] = min(nxt[i][j + 1], mn);
}
}
for (int l = 2; l <= block; l++) {
for (int i = 1; i + l - 1 <= block; i++) {
int k = i + l - 1;
calc(i, k);
for (int j = L[k]; j <= R[k]; j++)
pre[i][j] = min(pre[i][j - 1], min(pre[i + 1][j], ans[j]));
}
for (int i = block; i - l + 1 >= 1; i--) {
int k = i - l + 1;
calc(i, k);
for (int j = R[k]; j >= L[k]; j--)
nxt[i][j] = min(nxt[i][j + 1], min(nxt[i - 1][j], ans[j]));
}
}
}
int tmp[N], tmp1[N], tmp2[N];
int query(int l, int r) {
int p = pos[l], q = pos[r], res = 2e9;
if (p == q) {
int tot = 0;
for (int i = L[p]; i <= R[p]; i++)
if(l <= b[i].second && b[i].second <= r) tmp[++tot] = b[i].first;
for (int i = 1; i < tot; i++)
cmin(res, tmp[i + 1] - tmp[i]);
return res;
}
int tot1 = 0, tot2 = 0;
for (int i = L[p]; i <= R[p]; i++)
if (l <= b[i].second && b[i].second <= r) tmp1[++tot1] = b[i].first;
for (int i = L[q]; i <= R[q]; i++)
if (l <= b[i].second && b[i].second <= r) tmp2[++tot2] = b[i].first;
merge(tmp1 + 1, tmp1 + tot1 + 1, tmp2 + 1, tmp2 + tot2 + 1, tmp + 1);
for (int i = 1; i < tot1 + tot2; i++)
cmin(res, tmp[i + 1] - tmp[i]);
return min(res, min(nxt[q - 1][l], pre[p + 1][r]));
}
void solve() {
int m; scanf("%d", &m);
while (m--) {
int l, r; scanf("%d %d", &l, &r);
printf("%d\n", query(l, r));
}
}
int main() {
init(), solve();
}
AC 自动机
不妨把每个前缀看作一个状态,fail 树的意义为存在的最长后缀,tr 指向加该字母后的存在的最长后缀。所有为给定串的后缀的状态处在 沿 tr 走到的最终节点 在 fail 树上的所有祖先。
若 \(p \in \text{subtree}(q)\),则 \(p\) 代表的状态是 \(q\) 代表的状态的后缀。
ACAM 除了能够进行字符串匹配,还常与动态规划相结合,因为它精确刻画了文本串与 所有 模式串的匹配情况。同时,\(\delta\) 函数自然地为动态规划的转移指明了方向。因此,当遇到形如 “不能出现若干单词” 的字符串 计数或最优化 问题,可以考虑在 ACAM 上 DP,将 ACAM 的状态写进 DP 的一个维度。
int tot[N], tr[N][26], cnt, fail[N];
int init() {
++cnt;
memset(tr[cnt], 0, sizeof(tr[cnt]));
fail[cnt] = tot[cnt] = 0;
return cnt;
}
void insert(string &s) {
int cur = 0;
for (int i = 0; i < s.size(); i++) {
if (!tr[cur][s[i] - '0']) tr[cur][s[i] - '0'] = init();
cur = tr[cur][s[i] - '0'];
}
++tot[cur];
}
queue<int> q;
void build() {
memset(fail, 0, sizeof(fail));
for (int i = 0; i < 26; i++) if (tr[0][i]) q.push(tr[0][i]);
while (!q.empty()) {
int x = q.front(); q.pop(); tot[x] += tot[fail[x]];
for (int i = 0; i < 26; i++) {
if (tr[x][i]) fail[tr[x][i]] = tr[fail[x]][i], q.push(tr[x][i]);
else tr[x][i] = tr[fail[x]][i];
}
}
}
SAM
SAM 以高度压缩的方式储存了一个串的所有子串,每个节点是一个 endpos 等价类集合,长度连续。
SAM 接受给定字符串的所有后缀。
fa 指向的是该等价类最短节点长度再减一对应节点所在等价类。
a[p].len - a[a[p].fa].len
即为该等价类的节点个数。
可以线段树合并维护 endpos 集合。空间多开一倍就行。
沿着 fa 树往下走的过程是往后加字符而等价类分裂的过程。fa 树叶子按 dfn 序排列构成 SA。
SAM 的 fa 树是反串后缀树。
struct node {
int t[26], f, len;
} a[M << 1];
int las = 1, cnt = 1;
vector<int> e[M << 1];
int w[M << 1];
void ins(int c) {
int p = las, np = ++cnt; las = np; a[np].len = a[p].len + 1;
w[np] = 1;
for (; p && !a[p].t[c]; p = a[p].f) a[p].t[c] = np;
if(!p) return a[np].f = 1, void();
int q = a[p].t[c];
if(a[q].len == a[p].len + 1) return a[np].f = q, void();
else {
int nq = ++cnt; a[nq] = a[q]; a[nq].len = a[p].len + 1;
a[np].f = a[q].f = nq;
for (; p && a[p].t[c] == q; p = a[p].f) a[p].t[c] = nq;
}
}
void pre() {
for (int i = 2; i <= cnt; i++) e[a[i].f].push_back(i);
}
LL ans = 0;
void dfs(int u) {
for (auto v : e[u]) dfs(v), w[u] += w[v];
// do something.
}
本文来自博客园,作者:purplevine,转载请注明原文链接:https://www.cnblogs.com/purplevine/p/16743012.html