模板复习
没几天就要退役了\(QAQ\),赶紧复习下板子。
慢慢补
目录
高精
不久前打过,传送门。
数学、数论
- 线性筛
模板传送门
模板题仅筛素数。这里包括筛欧拉函数及因数个数。
#include<cstdio>
using namespace std;
const int N = 1e7 + 10;
int pr[N >> 2];
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
int main()
{
int i, j, n, m, l = 0;
n = re();
m = re();
v[0] = v[1] = 1;
for (i = 2; i <= n; i++)
{
if (!v[i])
pr[++l] = i;
for (j = 1; j <= l; j++)
{
if (i * pr[j] > n)
break;
v[i * pr[j]] = 1;
if (!(i % pr[j]))
break;
}
}
for (i = 1; i <= m; i++)
v[re()] ? printf("No\n") : printf("Yes\n");
return 0;
}
//筛欧拉函数
#include<cstdio>
using namespace std;
const int N = 1e7 + 10;
int pr[N >> 2], phi[N];
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
int main()
{
int i, j, n, m, l = 0;
n = re(); m = re();
v[0] = v[1] = phi[1] = 1;
for (i = 2; i < n; i++)
{
if (!v[i])
pr[++l] = i, phi[i] = i - 1;
for (j = 1; j <= l; j++)
{
if (i * pr[j] > n)
break;
v[i * pr[j]] = 1;
phi[i * pr[j]] = phi[i] * (pr[j] - 1);
if (!(i % pr[j]))
{
phi[i * pr[j]] = phi[i] * pr[j];
break;
}
}
}
for (i = 1; i <= m; i++)
printf("%d\n", phi[re()]);
return 0;
}
//筛因数个数
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e6 + 10;
const int mod = 1073741824;
int pr[N], Mipr[N], Ndiv[N];//Mipr最小质因子个数 Ndiv因数个数
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
int main()
{
int i, j, k, n, m, x, y, z, l = 0;
n = re();
Ndiv[1] = 1;
for (i = 2; i <= n; i++)
{
if (!v[i])
pr[++l] = i, Mipr[i] = 1, Ndiv[i] = 2;
for (j = 1; j <= l && i * pr[j] <= n; j++)
{
v[i * pr[j]] = 1;
if (!(i % pr[j]))
{
Mipr[i * pr[j]] = Mipr[i] + 1;
Ndiv[i * pr[j]] = Ndiv[i] / (Mipr[i] + 1) * (Mipr[i] + 2);
break;
}
Mipr[i * pr[j]] = 1;
Ndiv[i * pr[j]] = Ndiv[i] << 1;
}
}
return 0;
}
- 快速幂
模板传送门
#include<cstdio>
using namespace std;
int mod;
inline int ksm(int x, int y)
{
int s = 1;
for (; y; y >>= 1, x = 1LL * x * x % mod)
if (y & 1)
s = 1LL * s * x % mod;
return s % mod;
}
int main()
{
int x, y;
scanf("%d%d%d", &x, &y, &mod);
printf("%d^%d mod %d=%d", x, y, mod, ksm(x, y));
return 0;
}
- 线性推逆元
模板传送门
#include<cstdio>
using namespace std;
const int N = 3e6 + 10;
int inv[N];
int main()
{
int i, n, mod;
scanf("%d%d", &n, &mod);
for (printf("%d\n", inv[1] = 1), i = 2; i <= n; i++)
printf("%d\n", inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod);
return 0;
}
- 扩展欧几里得
模板传送门
并没有找到什么好的模板,只好用这道\(NOIP\)充数了,主要是记录\(exgcd\)。
#include<cstdio>
using namespace std;
typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (!b)
{
x = 1; y = 0;
return a;
}
ll gcd = exgcd(b, a % b, y, x);
y -= a / b * x;
return gcd;
}
int main()
{
ll a, b, x, y;
scanf("%lld%lld", &a, &b);
exgcd(a, b, x, y);
printf("%lld", (x + b) % b);
return 0;
}
- 卢卡斯定理
模板传送门
#include<cstdio>
using namespace std;
const int N = 1e5 + 10;
int fac[N], inv[N], mod;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
long long C(int x, int y)
{
if (x < y)
return 0;
if (!y || !(x ^ y))
return 1;
if (x < mod && y < mod)
return 1LL * fac[x] * inv[fac[y]] % mod * inv[fac[x - y]] % mod;
return 1LL * C(x % mod, y % mod) * C(x / mod, y / mod) % mod;
}
int main()
{
int i, n, m, T;
T = re();
while (T--)
{
n = re(); m = re(); mod = re();
fac[1] = inv[1] = 1;
for (i = 2; i <= mod; i++)
fac[i] = 1LL * fac[i - 1] * i % mod, inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
printf("%lld\n", C(n + m, m));
}
return 0;
}
\(ST\)表
模板传送门
求的是最大值。
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 1e5 + 10;
int f[N][18], L[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline int maxn(int x, int y){ return x > y ? x : y; }
int main()
{
int i, j, n, m, k, x, y;
n = re();
m = re();
for (i = 1; i <= n; i++)
{
f[i][0] = re();
L[i] = log2(i);
}
for (j = 1; j <= L[n]; j++)
for (i = 1; i + (1 << j) - 1 <= n; i++)
f[i][j] = maxn(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
for (i = 1; i <= m; i++)
{
x = re();
y = re();
k = L[y - x + 1];
printf("%d\n", maxn(f[x][k], f[y - (1 << k) + 1][k]));
}
return 0;
}
数据结构
- 并查集
模板传送门
#include<cstdio>
using namespace std;
const int N = 1e4 + 10;
int fa[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
int fin(int x)
{
if (!(fa[x] ^ x))
return x;
return fa[x] = fin(fa[x]);
}
int main()
{
int i, n, m, x, y, p;
n = re();
m = re();
for (i = 1; i <= n; i++)
fa[i] = i;
for (i = 1; i <= m; i++)
{
p = re();
x = re();
y = re();
if (p ^ 1)
fin(x) ^ fin(y) ? printf("N\n") : printf("Y\n");
else
{
x = fin(x);
y = fin(y);
if (x ^ y)
fa[x] = y;
}
}
return 0;
}
- 堆(二叉堆,优先队列)
只会用水
模板传送门
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
priority_queue<int, vector<int>, greater<int> >q;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
int main()
{
int i, n, p;
n = re();
for (i = 1; i <= n; i++)
{
p = re();
if (p ^ 1)
{
if (p ^ 2)
q.pop();
else
printf("%d\n", q.top());
}
else
q.push(re());
}
return 0;
}
- 单调栈
模板传送门
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int sta[N], wid[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline ll maxn(ll x, ll y) { return x > y ? x : y; }
int main()
{
int i, top, n, x, L;
ll ma;
while (n = re())
{
for (i = 1, top = ma = 0; i <= n + 1; i++)
{
x = (i ^ (n + 1) ? re() : 0);
if (sta[top] <= x)
sta[++top] = x, wid[top] = 1;
else
{
for (L = 0; sta[top] > x; top--)
L += wid[top], ma = maxn(ma, 1LL * L * sta[top]);
sta[++top] = x; wid[top] = L + 1;
}
}
printf("%lld\n", ma);
}
return 0;
}
- 单调队列
模板传送门
#include<cstdio>
using namespace std;
const int N = 1e6 + 10;
int qma[N], qmi[N], a[N], ans[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline int maxn(int x, int y) { return x > y ? x : y; }
inline int minn(int x, int y) { return x < y ? x : y; }
int main()
{
int i, n, m, lma = 1, rma = 0, lmi = 1, rmi = 0;
n = re(); m = re();
for (i = 1; i <= n; i++)
a[i] = re();
for (i = 1; i < m; i++)
{
for (; lma <= rma && a[qma[rma]] <= a[i]; rma--);
for (; lmi <= rmi && a[qmi[rmi]] >= a[i]; rmi--);
qma[++rma] = qmi[++rmi] = i;
}
for (i = m; i <= n; i++)
{
for (; lma <= rma && i - qma[lma] + 1 > m; lma++);
for (; lmi <= rmi && i - qmi[lmi] + 1 > m; lmi++);
for (; lma <= rma && a[qma[rma]] <= a[i]; rma--);
for (; lmi <= rmi && a[qmi[rmi]] >= a[i]; rmi--);
qma[++rma] = qmi[++rmi] = i;
printf("%d ", a[qmi[lmi]]); ans[i] = a[qma[lma]];
}
for (i = m, printf("\n"); i <= n; i++)
printf("%d ", ans[i]);
return 0;
}
- 字符串
模板传送门
#include<cstdio>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const int N = 1e4 + 10;
const int base = 1331;
ull a[N];
inline ull re_l()
{
ull x = 0;
char c = getchar();
for (; (c < '0' || c > '9') && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z'); c = getchar());
for (; (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); c = getchar())
x = x * base + c;
return x;
}
int main()
{
int i, n, s = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++)
a[i] = re_l();
sort(a + 1, a + n + 1);
for (i = 1; i <= n; i++)
if (a[i] ^ a[i - 1] || !(i ^ 1))
s++;
printf("%d", s);
return 0;
}
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;
int nex[N], f[N];
char a[N], b[N];
int main()
{
int i, j, n, m;
scanf("%s%s", a + 1, b + 1);
n = strlen(a + 1); m = strlen(b + 1);
for (i = 2, j = 0; i <= m; i++)
{
for (; j && b[i] != b[j + 1]; j = nex[j]);
nex[i] = (b[i] == b[j + 1] ? ++j : j);
}
for (i = 1, j = 0; i <= n; i++)
{
for (; j && (!(j ^ m) || a[i] != b[j + 1]); j = nex[j]);
f[i] = (a[i] == b[j + 1] ? ++j : j);
if (!(j ^ m))
printf("%d\n", i - j + 1);
}
for (i = 1; i <= m; i++)
printf("%d ", nex[i]);
return 0;
}
- 树
模板传送门
#include<cstdio>
using namespace std;
const int N = 5e5 + 10;
int trie[N][30], a[55], l, po = 1;
bool v[N], ed[N];
inline void re_l()
{
char c = getchar();
for (; c < 'a' || c > 'z'; c = getchar());
for (l = 0; c >= 'a' && c <= 'z'; c = getchar())
a[++l] = c - 'a' + 1;
}
inline void ins()
{
int i, nw = 1;
for (i = 1; i <= l; i++)
nw = (trie[nw][a[i]] ? trie[nw][a[i]] : trie[nw][a[i]] = ++po);
ed[nw] = 1;
}
inline int fin()
{
int i, nw = 1;
for (i = 1; i <= l && nw; i++)
nw = trie[nw][a[i]];
if (!nw || !ed[nw]) return 0;
return v[nw] ? 2 : v[nw] = 1;
}
int main()
{
int i, n, m, x;
scanf("%d", &n);
for (i = 1; i <= n; i++)
re_l(), ins();
scanf("%d", &m);
for (i = 1; i <= m; i++)
re_l(), x = fin(), (x ? (x ^ 1 ? printf("REPEAT\n") : printf("OK\n")) : printf("WRONG\n"));
return 0;
}
- 树状数组
模板传送门
#include<cstdio>
using namespace std;
const int N = 5e5 + 10;
int C[N], n;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline int lowbit(int x) { return x & -x; }
inline void add(int x, int y) { for (; x <= n; x += lowbit(x)) C[x] += y; }
inline int ask(int x)
{
int s = 0;
for (; x; x -= lowbit(x))
s += C[x];
return s;
}
int main()
{
int i, m, p, x, y;
n = re(); m = re();
for (i = 1; i <= n; i++)
add(i, re());
for (i = 1; i <= m; i++)
{
p = re() - 1; x = re(); y = re();
p ? (void)printf("%d\n", ask(y) - ask(x - 1)) : add(x, y);
}
return 0;
}
- 线段树
模板传送门
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll S[N << 2], a[N], ad[N << 2];
inline ll re()
{
ll x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
void pp(int r){ S[r] = S[r << 1] + S[r << 1 | 1]; }
void pn(int r, int x, int y)
{
ll &k = ad[r];
if (k)
{
int lx = r << 1, ly = r << 1 | 1, mid = (x + y) >> 1;
ad[lx] += k;
ad[ly] += k;
S[lx] += k * (mid - x + 1);
S[ly] += k * (y - mid);
k = 0;
}
}
void bu(int r, int x, int y)
{
if (!(x ^ y))
S[r] = a[x];
else
{
int mid = (x + y) >> 1;
bu(r << 1, x, mid);
bu(r << 1 | 1, mid + 1, y);
pp(r);
}
}
void upd(int r, int x, int y, int ql, int qr, ll k)
{
if (ql <= x && y <= qr)
{
S[r] += k * (y - x + 1);
ad[r] += k;
return;
}
int mid = (x + y) >> 1;
pn(r, x, y);
if (ql <= mid)
upd(r << 1, x, mid, ql, qr, k);
if (mid < qr)
upd(r << 1 | 1, mid + 1, y, ql, qr, k);
pp(r);
}
ll qu(int r, int x, int y, int ql, int qr)
{
if (ql <= x && y <= qr)
return S[r];
int mid = (x + y) >> 1;
ll s = 0;
pn(r, x, y);
if (ql <= mid)
s += qu(r << 1, x, mid, ql, qr);
if (mid < qr)
s += qu(r << 1 | 1, mid + 1, y, ql, qr);
return s;
}
int main()
{
int i, n, m, x, y, p;
n = re();
m = re();
for (i = 1; i <= n; i++)
a[i] = re();
bu(1, 1, n);
for (i = 1; i <= m; i++)
{
p = re();
x = re();
y = re();
if (p ^ 2)
upd(1, 1, n, x, y, re());
else
printf("%lld\n", qu(1, 1, n, x, y));
}
return 0;
}
- 分块
模板传送门
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int M = 350;
ll a[N], S[M], ad[M];
int L[N], R[N], pos[N];
inline ll re()
{
ll x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
void modify(int x, int y, ll k)
{
int l = pos[x], r = pos[y], i;
if (!(l ^ r))
{
for (i = x; i <= y; i++)
a[i] += k;
S[l] += k * (y - x + 1);
return;
}
for (i = x; i <= R[l]; i++)
a[i] += k;
S[l] += k * (R[l] - x + 1);
for (i = l + 1; i < r; i++)
ad[i] += k;
for (i = L[r]; i <= y; i++)
a[i] += k;
S[r] += k * (y - L[r] + 1);
}
ll qu(int x, int y)
{
int l = pos[x], r = pos[y], i;
ll s = 0;
if (!(l ^ r))
{
for (i = x; i <= y; i++)
s += a[i];
return s + ad[l] * (y - x + 1);
}
for (i = x; i <= R[l]; i++)
s += a[i];
s += ad[l] * (R[l] - x + 1);
for (i = l + 1; i < r; i++)
s += S[i] + ad[i] * (R[i] - L[i] + 1);
for (i = L[r]; i <= y; i++)
s += a[i];
return s + ad[r] * (y - L[r] + 1);
}
int main()
{
int i, j, n, m, x, y, p, k;
n = re(); m = re(); k = sqrt(n);
for (i = 1; i <= n; i++)
a[i] = re();
for (i = 1; i <= k; i++)
L[i] = (i - 1) * k + 1, R[i] = i * k;
if (R[k] < n)
L[k + 1] = R[k] + 1, R[++k] = n;
for (i = 1; i <= k; i++)
for (j = L[i]; j <= R[i]; j++)
S[i] += a[j], pos[j] = i;
for (i = 1; i <= m; i++)
{
p = re() - 1; x = re(); y = re();
p ? (void)printf("%lld\n", qu(x, y)) : modify(x, y, re());
}
return 0;
}
模板传送门
仅含平衡树的基本操作。
#include<cstdio>
using namespace std;
const int N = 1e5 + 10;
struct sp {
int so[2], s, v, si, fa;
};
sp tr[N];
int SP, ro;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline int maxn(int x, int y){ return x > y ? x : y; }
inline int minn(int x, int y){ return x < y ? x : y; }
inline void pp(int x){ tr[x].si = tr[tr[x].so[0]].si + tr[tr[x].so[1]].si + tr[x].s; }
inline int who(int x){ return tr[tr[x].fa].so[0] ^ x ? 1 : 0; }
inline void ch(int x, int fa, int lr)
{
tr[fa].so[lr] = x;
tr[x].fa = fa;
}
void rtt(int x)
{
int y = tr[x].fa, r = tr[y].fa, soy = who(x), sor = who(y);
ch(tr[x].so[soy ^ 1], y, soy);
ch(y, x, soy ^ 1);
ch(x, r, sor);
pp(y);
pp(x);
}
void sy(int x, int y)
{
int z;
if (!(ro ^ y))
ro = x;
y = tr[y].fa;
while (tr[x].fa ^ y)
{
z = tr[x].fa;
if (!(tr[z].fa ^ y))
rtt(x);
else
{
who(x) ^ who(z) ? rtt(x) : rtt(z);
rtt(x);
}
}
}
inline int newnode(int x, int fa)
{
tr[++SP].fa = fa;
tr[SP].v = x;
tr[SP].si = tr[SP].s = 1;
return SP;
}
void is(int x)
{
if (!ro)
ro = newnode(x, 0);
else
for (int y, k = ro; ; k = tr[k].so[y])
{
tr[k].si++;
if (!(tr[k].v ^ x))
{
tr[k].s++;
sy(k, ro);
return;
}
if (!tr[k].so[y = x < tr[k].v ? 0 : 1])
{
int nw = newnode(x, k);
tr[k].so[y] = nw;
sy(nw, ro);
return;
}
}
}
inline int fin(int x)
{
for (int k = ro; k; k = tr[k].so[x < tr[k].v ? 0 : 1])
if (!(tr[k].v ^ x))
{
sy(k, ro);
return k;
}
return 0;
}
void dt(int x)
{
int k = fin(x), y;
if (!k)
return;
if (tr[k].s > 1)
{
tr[k].s--;
tr[k].si--;
return;
}
if (!tr[k].so[0] && !tr[k].so[1])
{
ro = 0;
return;
}
if (!tr[k].so[0])
{
ro = tr[k].so[1];
tr[ro].fa = 0;
return;
}
if (!tr[k].so[1])
{
ro = tr[k].so[0];
tr[ro].fa = 0;
return;
}
for (y = tr[k].so[0]; tr[y].so[1]; y = tr[y].so[1]);
sy(y, tr[k].so[0]);
ch(tr[k].so[1], y, 1);
ro = y;
tr[y].fa = 0;
pp(y);
}
inline int qu_rk(int x){ return tr[tr[fin(x)].so[0]].si + 1; }
int qu_nu(int x)
{
for (int k = ro, nw; ; )
{
nw = tr[k].si - tr[tr[k].so[1]].si;
if (x > tr[tr[k].so[0]].si && x <= nw)
{
sy(k, ro);
return tr[k].v;
}
if (x < nw)
k = tr[k].so[0];
else
{
k = tr[k].so[1];
x -= nw;
}
}
}
inline int qu_pre(int x)
{
int s = -1e9;
for (int k = ro; k; k = tr[k].so[x <= tr[k].v ? 0 : 1])
if (x > tr[k].v)
s = maxn(s, tr[k].v);
return s;
}
inline int qu_suc(int x)
{
int s = 1e9;
for (int k = ro; k; k = tr[k].so[x >= tr[k].v ? 1 : 0])
if (x < tr[k].v)
s = minn(s, tr[k].v);
return s;
}
int main()
{
int i, n, p;
n = re();
for (i = 1; i <= n; i++)
{
p = re();
if (!(p ^ 1))
is(re());
else
if (!(p ^ 2))
dt(re());
else
if (!(p ^ 3))
printf("%d\n", qu_rk(re()));
else
if (!(p ^ 4))
printf("%d\n", qu_nu(re()));
else
if (!(p ^ 5))
printf("%d\n", qu_pre(re()));
else
printf("%d\n", qu_suc(re()));
}
return 0;
}
- 树链剖分
模板传送门
#include<cstdio>
using namespace std;
const int N = 1e5 + 10;
const int M = N << 1;
int fi[N], ne[M], di[M], val[N], si[N], fa[N], id[N], fid[N], son[N], top[N], S[M << 1], ad[M << 1], dep[N], l = 1, cnt, mod, n;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y) { di[++l] = y; ne[l] = fi[x]; fi[x] = l; }
inline void sw(int &x, int &y) { int z = x; x = y; y = z; }
void dfs_1(int x)
{
int i, y;
si[x] = 1;
for (i = fi[x]; i; i = ne[i])
if ((y = di[i]) ^ fa[x])
{
fa[y] = x; dep[y] = dep[x] + 1;
dfs_1(y); si[x] += si[y];
if (si[y] > si[son[x]])
son[x] = y;
}
}
void dfs_2(int x, int tp)
{
int i, y;
top[x] = tp; id[x] = ++cnt; fid[cnt] = x;
if (son[x])
dfs_2(son[x], tp);
for (i = fi[x]; i; i = ne[i])
{
y = di[i];
if (y ^ fa[x] && y ^ son[x])
dfs_2(y, y);
}
}
inline void pushup(int r) { S[r] = (1LL * S[r << 1] + S[r << 1 | 1]) % mod; }
inline void pushdown(int r, int x, int y)
{
int &k = ad[r];
if (k)
{
int lx = r << 1, ly = r << 1 | 1, mid = (x + y) >> 1;
ad[lx] = (1LL * ad[lx] + k) % mod; ad[ly] = (1LL * ad[ly] + k) % mod;
S[lx] = (1LL * k * (mid - x + 1) + S[lx]) % mod;
S[ly] = (1LL * k * (y - mid) + S[ly]) % mod;
k = 0;
}
}
void bu(int r, int x, int y)
{
if (x ^ y)
{
int mid = (x + y) >> 1;
bu(r << 1, x, mid);
bu(r << 1 | 1, mid + 1, y);
pushup(r);
}
else
S[r] = val[fid[x]];
}
void modify(int r, int x, int y, int ql, int qr, int k)
{
if (ql <= x && y <= qr)
{
ad[r] = (1LL * ad[r] + k) % mod;
S[r] = (1LL * k * (y - x + 1) + S[r]) % mod;
return;
}
int mid = (x + y) >> 1;
pushdown(r, x, y);
if (ql <= mid)
modify(r << 1, x, mid, ql, qr, k);
if (mid < qr)
modify(r << 1 | 1, mid + 1, y, ql, qr, k);
pushup(r);
}
int qu(int r, int x, int y, int ql, int qr)
{
if (ql <= x && y <= qr)
return S[r];
int mid = (x + y) >> 1, s = 0;
pushdown(r, x, y);
if (ql <= mid)
s = (1LL * s + qu(r << 1, x, mid, ql, qr)) % mod;
if (mid < qr)
s = (1LL * s + qu(r << 1 | 1, mid + 1, y, ql, qr)) % mod;
return s;
}
void tr_modify(int x, int y, int z)
{
for (; top[x] ^ top[y]; y = fa[top[y]])
{
if (dep[top[x]] > dep[top[y]])
sw(x, y);
modify(1, 1, n, id[top[y]], id[y], z);
}
if (id[x] > id[y])
sw(x, y);
modify(1, 1, n, id[x], id[y], z);
}
int tr_qu(int x, int y)
{
int s = 0;
for (; top[x] ^ top[y]; y = fa[top[y]])
{
if (dep[top[x]] > dep[top[y]])
sw(x, y);
s = (1LL * s + qu(1, 1, n, id[top[y]], id[y])) % mod;
}
if (id[x] > id[y])
sw(x, y);
return s = (1LL * s + qu(1, 1, n, id[x], id[y])) % mod;
}
int main()
{
int i, m, ro, p, x, y;
n = re(); m = re(); ro = re(); mod = re();
for (i = 1; i <= n; i++)
val[i] = re();
for (i = 1; i < n; i++)
{
x = re(); y = re();
add(x, y); add(y, x);
}
dep[ro] = 1; dfs_1(ro); dfs_2(ro, ro);
bu(1, 1, n);
for (i = 1; i <= m; i++)
{
p = re(); x = re();
if (p ^ 4)
{
y = re();
if (p ^ 1)
p ^ 3 ? (void)printf("%d\n", tr_qu(x, y)) : modify(1, 1, n, id[x], id[x] + si[x] - 1, y);
else
tr_modify(x, y, re());
}
else
printf("%d\n", qu(1, 1, n, id[x], id[x] + si[x] - 1));
}
return 0;
}
数位\(DP\)
虽然是套路,但这个模板还是挺灵活的。
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = ...;
ll f[N][...]...;//看题目定状态
int a[N];
inline ll re()
{
ll x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
//有些题不需要考虑前导零,有些则需要
ll dfs(int pos/*剩余枚举位数*/,.../*一些要记录的状态*/, int lm/*当前位是否有限制*/, int zero/*是否有前导零*/)
{
if (pos < 0)//枚举结束,返回
return s;
...//有些题可能要剪枝
if (!lm && !zero && f[pos][s] > -1)//如果没有限制,返回记忆化的数据
return f[pos][...]...;
int i, k = lm ? a[pos] : 9;//判断枚举上界
ll S = 0;
for (i = 0; i <= k; i++)//枚举该位
{
if ()
...
else
if ()
...//根据题目的不同操作
S += dfs(pos - 1,.../*状态转移*/, lm && i == a[pos], zero && !i);//这里比较灵活,视题目而定
}
if (!lm && !zero)//没有限制则记忆化
return f[pos][...]... = S;
return S;
}
ll calc(ll x)//拆分数位
{
int k = 0;
memset(f, -1, sizeof(f));//一般初始化为-1,有些题目只需初始化一次
while (x > 0)
{
a[k++] = x % 10;
x /= 10;
}
return dfs(k - 1,.../*初始状态*/, 1, 1);
}
int main()
{
ll x, y;
x = re();
y = re();
printf("%d", calc(y) - calc(x - 1));//前缀和思想
return 0;
}
图论
单源最短路径
- (堆优化)
模板传送门
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
struct dd {
int x, D;
bool operator < (const dd &b) const { return D > b.D; }
};
int fi[N], di[M], ne[M], da[M], dis[N], l;
bool v[N];
priority_queue<dd>q;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y, int z)
{
di[++l] = y;
da[l] = z;
ne[l] = fi[x];
fi[x] = l;
}
void dij(int st)
{
int i, x, y;
memset(dis, 60, sizeof(dis));
dis[st] = 0;
q.push((dd){st, 0});
while (!q.empty())
{
x = q.top().x;
q.pop();
if (v[x])
continue;
v[x] = 1;
for (i = fi[x]; i; i = ne[i])
if (dis[y = di[i]] > dis[x] + da[i])
q.push((dd){y, dis[y] = dis[x] + da[i]});
}
}
int main()
{
int i, x, y, n, m, z, st;
n = re();
m = re();
st = re();
for (i = 1; i <= m; i++)
{
x = re();
y = re();
z = re();
add(x, y, z);
}
dij(st);
for (i = 1; i <= n; i++)
printf("%d ", dis[i]);
return 0;
}
模板传送门
关于,他已经死了,让我们挂一张遗像
#include<cstdio>
using namespace std;
const int N = 1e4 + 10;
const int M = 5e5 + 10;
const int L = 5e5;
const int K = (1LL << 31) - 1;
int fi[N], di[M], ne[M], da[M], dis[N], q[M], l;
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y, int z)
{
di[++l] = y;
da[l] = z;
ne[l] = fi[x];
fi[x] = l;
}
void spfa(int st)
{
int i, x, y, head = 0, tail = 1;
q[1] = st;
dis[st] = 0;
while (head ^ tail)
{
if (!(++head ^ L))
head = 1;
x = q[head];
v[x] = 0;
for (i = fi[x]; i; i = ne[i])
if (dis[y = di[i]] > dis[x] + da[i])
{
dis[y] = dis[x] + da[i];
if (!v[y])
{
if (!(++tail ^ L))
tail = 1;
q[tail] = y;
v[y] = 1;
}
}
}
}
int main()
{
int i, x, y, n, m, st, z;
n = re();
m = re();
st = re();
for (i = 1; i <= m; i++)
{
x = re();
y = re();
z = re();
add(x, y, z);
}
for (i = 1; i <= n; i++)
dis[i] = K;
spfa(st);
for (i = 1; i <= n; i++)
printf("%d ", dis[i]);
return 0;
}
多源最短路径
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 510;
int a[N][N], b[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline int minn(int x, int y){ return x < y ? x : y; }
int main()
{
int i, j, k, n, m, l, x, y, mi = 1e9, mi_id;
n = re();
l = re();
m = re();
for (i = 1; i <= l; i++)
b[i] = re();
memset(a, 60, sizeof(a));
for (i = 1; i <= m; i++)
{
x = re();
y = re();
a[y][x] = a[x][y] = re();
}
for (i = 1; i <= n; i++)
a[i][i] = 0;
for (k = 1; k <= n; k++)
for (i = 1; i <= n; i++)
if (i ^ k)
for (j = 1; j < i; j++)
a[i][j] = a[j][i] = minn(a[i][j], a[i][k] + a[k][j]);
for (i = 1; i <= n; i++)
{
int s = 0;
for (j = 1; j <= l; j++)
s += a[i][b[j]];
if (s < mi)
{
mi = s;
mi_id = i;
}
}
printf("%d", mi_id);
return 0;
}
最小生成树
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 5010;
const int M = 2e5 + 10;
struct dd {
int x, y, z;
};
dd a[M];
int fa[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
int fin(int x)
{
if (!(fa[x] ^ x))
return x;
return fa[x] = fin(fa[x]);
}
bool comp(dd x, dd y){ return x.z < y.z; }
int main()
{
int i, n, m, x, y, s = 0, k = 0;
n = re();
m = re();
for (i = 1; i <= m; i++)
{
a[i].x = re();
a[i].y = re();
a[i].z = re();
}
sort(a + 1, a + m + 1, comp);
for (i = 1; i <= n; i++)
fa[i] = i;
for (i = 1; i <= m && k ^ (n - 1); i++)
{
x = fin(a[i].x);
y = fin(a[i].y);
if (x ^ y)
{
fa[x] = y;
s += a[i].z;
k++;
}
}
k ^ (n - 1) ? printf("orz") : printf("%d", s);
return 0;
}
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 5e3 + 10;
int a[N][N], dis[N], n;
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline int minn(int x, int y) { return x < y ? x : y; }
void prim()
{
int i, j, x;
memset(dis, 60, sizeof(dis));
dis[1] = 0;
for (i = 1; i <= n; i++)
{
for (x = 0, j = 1; j <= n; j++)
if (!v[j] && (!x || dis[j] < dis[x]))
x = j;
v[x] = 1;
for (j = 1; j <= n; j++)
if (!v[j])
dis[j] = minn(dis[j], a[x][j]);
}
}
int main()
{
int i, m, x, y, s = 0;
n = re(); m = re();
memset(a, 60, sizeof(a));
for (i = 1; i <= m; i++)
{
x = re(); y = re();
a[x][y] = a[y][x] = re();
}
prim();
for (i = 1; i <= n; i++)
s += dis[i];
return printf("%d", s), 0;
}
树的直径
- 树形法
模板传送门
#include<cstdio>
using namespace std;
const int N = 1e5 + 10;
int di[N << 1], ne[N << 1], da[N << 1], fi[N], d[N], l = 1, ans;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y, int z) { di[++l] = y; da[l] = z; ne[l] = fi[x]; fi[x] = l; }
inline int maxn(int x, int y) { return x > y ? x : y; }
void dp(int x, int fa)
{
int i, y;
for (i = fi[x]; i; i = ne[i])
if ((y = di[i]) ^ fa)
{
dp(y, x);
ans = maxn(ans, d[x] + d[y] + da[i]);
d[x] = maxn(d[x], d[y] + da[i]);
}
}
int main()
{
int i, n, m, x, y, z;
n = re(); m = re();
for (i = 1; i <= m; i++)
{
x = re(); y = re(); z = re();
add(x, y, z); add(y, x, z);
}
dp(1, 0);
return printf("%d", ans), 0;
}
法
模板传送门
注意有负边权时,并不能跑出正确的直径。
#include<cstdio>
using namespace std;
const int N = 1e5 + 10;
int fi[N], di[N << 1], ne[N << 1], da[N << 1], ans, poi, l = 1;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y, int z) { di[++l] = y; da[l] = z; ne[l] = fi[x]; fi[x] = l; }
void dfs(int x, int fa, int d)
{
int i, y;
if (ans < d)
ans = d, poi = x;
for (i = fi[x]; i; i = ne[i])
if ((y = di[i]) ^ fa)
dfs(y, x, d + da[i]);
}
int main()
{
int i, n, m, x, y, z;
n = re(); m = re();
for (i = 1; i <= m; i++)
{
x = re(); y = re(); z = re();
add(x, y, z); add(y, x, z);
}
dfs(1, 0, 0); ans = 0; dfs(poi, 0, 0);
return printf("%d", ans), 0;
}
\(LCA\)
- 倍增法
模板传送门
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 5e5 + 10;
const int M = 20;
int fi[N], di[N << 1], ne[N << 1], f[N][M], dep[N], l = 1, gn;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y) { di[++l] = y; ne[l] = fi[x]; fi[x] = l; }
inline void sw(int &x, int &y) { int z = x; x = y; y = z; }
void dfs(int x, int fa)
{
int i, y;
for (i = 1; i <= gn; i++)
f[x][i] = f[f[x][i - 1]][i - 1];
for (i = fi[x]; i; i = ne[i])
if ((y = di[i]) ^ fa)
{
f[y][0] = x;
dep[y] = dep[x] + 1;
dfs(y, x);
}
}
inline int lca(int x, int y)
{
int i;
if (dep[x] > dep[y])
sw(x, y);
for (i = gn; ~i; i--)
if (dep[f[y][i]] >= dep[x])
y = f[y][i];
if (!(x ^ y)) return x;
for (i = gn; ~i; i--)
if (f[x][i] ^ f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
int main()
{
int i, n, m, ro, x, y;
n = re(); m = re(); ro = re();
for (i = 1; i < n; i++)
{
x = re(); y = re();
add(x, y); add(y, x);
}
gn = log(n) / log(2); dep[ro] = 1; dfs(ro, 0);
for (i = 1; i <= m; i++)
{
x = re(); y = re();
printf("%d\n", lca(x, y));
}
return 0;
}
- 版
模板传送门
#include<cstdio>
using namespace std;
const int N = 5e5 + 10;
const int M = N << 1;
int fi[N], ne[M], di[M], ans[N], qu_fi[N], qu_di[M], qu_ne[M], fa[N], id[M], v[N], l = 1, qu_l = 1;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y) { di[++l] = y; ne[l] = fi[x]; fi[x] = l; }
inline void qu_add(int x, int y, int z) { qu_di[++qu_l] = y; id[qu_l] = z; qu_ne[qu_l] = qu_fi[x]; qu_fi[x] = qu_l; }
int fin(int x)
{
if (!(x ^ fa[x]))
return x;
return fa[x] = fin(fa[x]);
}
void tarjan(int x)
{
int i, y;
v[x] = 1;
for (i = fi[x]; i; i = ne[i])
if (!v[y = di[i]])
tarjan(y), fa[y] = x;
for (i = qu_fi[x]; i; i = qu_ne[i])
if (!(v[y = qu_di[i]] ^ 2))
ans[id[i]] = fin(y);
v[x] = 2;
}
int main()
{
int i, n, m, x, y, ro;
n = re(); m = re(); ro = re();
for (i = 1, fa[n] = n; i < n; i++)
{
x = re(); y = re(); fa[i] = i;
add(x, y); add(y, x);
}
for (i = 1; i <= m; i++)
{
x = re(); y = re();
qu_add(x, y, i); qu_add(y, x, i);
}
tarjan(ro);
for (i = 1; i <= m; i++)
printf("%d\n", ans[i]);
return 0;
}
\(Tarjan\)算法
- 边双连通分量(割边/桥)
并没有找到什么好的模板。就随便打了个。
#include<cstdio>
using namespace std;
const int N = 2e4 + 10;
const int M = 1e5 + 10;
int fi[N], di[M], ne[M], bl[N], dfn[N], low[N], l = 1, DCC, ti;
bool br[M];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y)
{
di[++l] = y;
ne[l] = fi[x];
fi[x] = l;
}
inline int minn(int x, int y){ return x < y ? x : y; }
void tarjan(int x, int la)
{
int i, y;
dfn[x] = low[x] = ++ti;
for (i = fi[x]; i; i = ne[i])
if (!dfn[y = di[i]])
{
tarjan(y, i);
low[x] = minn(low[x], low[y]);
if (low[y] > dfn[x])
br[i] = br[i ^ 1] = 1;
}
else
if (i ^ la ^ 1)
low[x] = minn(low[x], dfn[y]);
}
void dfs(int x)
{
int i, y;
bl[x] = DCC;
for (i = fi[x]; i; i = ne[i])
if (!bl[y = di[i]] && !br[i])
dfs(y);
}
int main()
{
int i, n, m, x, y;
n = re();
m = re();
for (i = 1; i <= m; i++)
{
x = re();
y = re();
add(x, y);
add(y, x);
}
for (i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i, 0);
for (i = 1; i <= n; i++)
if (!bl[i])
{
++DCC;
dfs(i);
}
printf("%d", DCC);
return 0;
}
- 强连通分量(割点)
模板传送门
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e4 + 10;
const int M = 1e5 + 10;
struct eg {
int x, y;
};
eg a[M];
int fi[N], ne[M], di[M], cfi[N], cne[M], cdi[M], val[N], Sval[N], bl[N], sta[N], dfn[N], low[N], dis[N], q[M], ru[N], l = 1, cl = 1, SCC, ti, top;
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y) { di[++l] = y; ne[l] = fi[x]; fi[x] = l; }
inline void cadd(int x, int y) { cdi[++cl] = y; cne[cl] = cfi[x]; cfi[x] = cl; ru[y]++; }
inline int maxn(int x, int y) { return x > y ? x : y; }
inline int minn(int x, int y) { return x < y ? x : y; }
void tarjan(int x)
{
int i, y;
dfn[x] = low[x] = ++ti;
sta[++top] = x; v[x] = 1;
for (i = fi[x]; i; i = ne[i])
if (!dfn[y = di[i]])
{
tarjan(y);
low[x] = minn(low[x], low[y]);
}
else
if (v[y])
low[x] = minn(low[x], dfn[y]);
if (!(low[x] ^ dfn[x]))
{
SCC++;
do
{
y = sta[top--];
Sval[SCC] += val[y];
bl[y] = SCC; v[y] = 0;
} while (x ^ y);
}
}
int topsort()
{
int i, x, y, ma = 0, head = 0, tail = 0;
memset(dis, 195, sizeof(dis));
for (i = 1; i <= SCC; i++)
if (!ru[i])
dis[i] = Sval[i], q[++tail] = i;
while (head ^ tail)
{
x = q[++head];
ma = maxn(ma, dis[x]);
for (i = cfi[x]; i; i = cne[i])
{
y = cdi[i];
dis[y] = maxn(dis[y], dis[x] + Sval[y]);
if (!(--ru[y]))
q[++tail] = y;
}
}
return ma;
}
int main()
{
int i, n, m;
n = re(); m = re();
for (i = 1; i <= n; i++)
val[i] = re();
for (i = 1; i <= m; i++)
{
a[i].x = re(); a[i].y = re();
add(a[i].x, a[i].y);
}
for (i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i);
for (i = 1; i <= m; i++)
if (bl[a[i].x] ^ bl[a[i].y])
cadd(bl[a[i].x], bl[a[i].y]);
return printf("%d", topsort()), 0;
}
//附裸的找割点
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 2e4 + 10;
const int M = 2e5 + 10;
int fi[N], ne[M], di[M], dfn[N], low[N], cut_poi[N], l = 1, ti, ro, poi_s;
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y) { di[++l] = y; ne[l] = fi[x]; fi[x] = l; }
inline int minn(int x, int y) { return x < y ? x : y; }
void tarjan(int x)
{
int i, y, k = 0;
dfn[x] = low[x] = ++ti;
for (i = fi[x]; i; i = ne[i])
if (!dfn[y = di[i]])
{
tarjan(y);
low[x] = minn(low[x], low[y]);
if (low[y] >= dfn[x])
if (!v[x] && (x ^ ro || (++k) > 1))
cut_poi[++poi_s] = x, v[x] = 1;
}
else
low[x] = minn(low[x], dfn[y]);
}
int main()
{
int i, n, m, x, y;
n = re(); m = re();
for (i = 1; i <= m; i++)
{
x = re(); y = re();
add(x, y); add(y, x);
}
for (i = 1; i <= n; i++)
if (!dfn[i])
ro = i, tarjan(i);
sort(cut_poi + 1, cut_poi + poi_s + 1);
printf("%d\n", poi_s);
for (i = 1; i <= poi_s; i++)
printf("%d ", cut_poi[i]);
return 0;
}
二分图匹配
- 匈牙利算法
模板传送门
二分图最大匹配模板。
简单记下二分图其它的内容。
二分图最小点覆盖,求最小的点集使得图中任意一条边都至少有一个端点属于这个点集,其值等于最大匹配数。
二分图最大独立集,求最大的点集使得任意两个点集中的点都没有一条边相连,其值等于二分图点数减去最大匹配数。
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 2e3 + 10;
const int M = 1e6 + 10;
int fi[N], ne[M], di[M], match[N], l = 1;
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y) { di[++l] = y; ne[l] = fi[x]; fi[x] = l; }
bool dfs(int x)
{
int i, y;
for (i = fi[x]; i; i = ne[i])
if (!v[y = di[i]])
{
v[y] = 1;
if (!match[y] || dfs(match[y]))
{
match[y] = x;
return true;
}
}
return false;
}
int main()
{
int i, n, m, e, x, y, s = 0;
n = re(); m = re(); e = re();
for (i = 1; i <= e; i++)
{
x = re(); y = re();
if (x > n || y > m) continue;
add(x, y + n);
}
for (i = 1; i <= n; i++)
{
memset(v, 0, sizeof(v));
if (dfs(i))
s++;
}
return printf("%d", s), 0;
}
网络流
(虽然感觉这玩意并没有什么用)
- 最大流(含当前弧优化)
模板传送门
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e4 + 10;
const int M = 2e5 + 10;
int fi[N], di[M], ne[M], da[M], de[N], cu[N], q[M], st, ed, l = 1;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y, int z)
{
di[++l] = y;
da[l] = z;
ne[l] = fi[x];
fi[x] = l;
}
inline int minn(int x, int y){ return x < y ? x : y; }
bool bfs()
{
memset(de, 0, sizeof(de));
int i, x, y, head = 0, tail = 1;
q[1] = st;
de[st] = 1;
while (head ^ tail)
{
x = q[++head];
for (i = fi[x]; i; i = ne[i])
if (!de[y = di[i]] && da[i] > 0)
{
de[y] = de[x] + 1;
if (!(y ^ ed))
return true;
q[++tail] = y;
}
}
return false;
}
int dfs(int x, int k)
{
if (!(x ^ ed))
return k;
int y, mi;
for (int &i = cu[x]; i; i = ne[i])
if (!(de[y = di[i]] ^ (de[x] + 1)) && da[i] > 0)
{
mi = dfs(y, minn(k, da[i]));
if (mi > 0)
{
da[i] -= mi;
da[i ^ 1] += mi;
return mi;
}
}
return 0;
}
int main()
{
int i, n, m, x, y, z, s = 0;
n = re();
m = re();
st = re();
ed = re();
for (i = 1; i <= m; i++)
{
x = re();
y = re();
z = re();
add(x, y, z);
add(y, x, 0);
}
while (bfs())
{
for (i = 1; i <= n; i++)
cu[i] = fi[i];
for (; (x = dfs(st, 1e9)) > 0; s += x);
}
printf("%d", s);
return 0;
}
- 费用流(,最小费用)
模板传送门
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 5010;
const int M = 1e5 + 10;
int fi[N], di[M], ne[M], da[M], co[M], q[M], flo[N], pre[N], dis[N], l = 1, st, ed;
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y, int z, int c) { di[++l] = y; da[l] = z; co[l] = c; ne[l] = fi[x]; fi[x] = l; }
inline int minn(int x, int y) { return x < y ? x : y; }
bool spfa()
{
int i, x, y, head = 0, tail = 1;
memset(dis, 60, sizeof(dis));
dis[st] = 0; q[1] = st; flo[st] = 1e9;
while (head ^ tail)
{
x = q[++head]; v[x] = 0;
for (i = fi[x]; i; i = ne[i])
if (dis[y = di[i]] > dis[x] + co[i] && da[i] > 0)
{
dis[y] = dis[x] + co[i];
pre[y] = i; flo[y] = minn(flo[x], da[i]);
if (!v[y])
q[++tail] = y, v[y] = 1;
}
}
return dis[ed] < 1e9;
}
int main()
{
int i, n, m, x, y, z, c, s = 0, f = 0;
n = re(); m = re(); st = re(); ed = re();
for (i = 1; i <= m; i++)
{
x = re(); y = re(); z = re(); c = re();
add(x, y, z, c); add(y, x, 0, -c);
}
while (spfa())
{
s += flo[ed] * dis[ed]; f += flo[ed];
for (x = ed; x ^ st; x = di[i ^ 1])
i = pre[x], da[i] -= flo[ed], da[i ^ 1] += flo[ed];
}
printf("%d %d", f, s);
return 0;
}
计算几何
(未完待续)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int eps = 1e-6;
struct poi { //点
double x, y;
poi() { x = y = 0; }
poi operator + (const poi& b) { poi c; c.x = x + b.x; c.y = y + b.y; return c; }
poi operator - (const poi& b) { poi c; c.x = x - b.x; c.y = y - b.y; return c; }
poi operator * (const double b) { poi c; c.x = x * b; c.y = y * b; return c; }
poi operator / (const double b) { poi c; c.x = x / b; c.y = y / b; return c; }
double O_len() { return sqrt(x * x + y * y); }//与原点距离
double X_ang() { return atan2(y, x); }//x轴起的角度
int Quadrant()//象限,注意包含xy轴
{
if (x > 0 && y >= 0) return 1;
if (x <= 0 && y > 0) return 2;
if (x < 0 && y <= 0) return 3;
if (x >= 0 && y < 0) return 4;
}
poi Spin(const poi& b, double Tang)//求此点绕点b旋转Tang后的点
{
poi c;
c.x = b.x + (x - b.x) * cos(Tang) - (y - b.y) * sin(Tang);
c.y = b.y + (y - b.y) * cos(Tang) + (x - b.x) * sin(Tang);
return c;
}
};
poi a[N];
struct line { //线
poi s, t;
double a, b, c, ang;//ax+by+c=0 与x轴正轴角度
line() { a = b = c = ang = 0; }
void init(poi x, poi y)
{
this->s = x; this->t = y; this->ang = (y - x).X_ang();
if (fabs(x.x - y.x) < eps)
a = 1, b = 0, c = -x.x;
else if (fabs(x.y - y.y) < eps)
a = 0, b = 1, c = -x.y;
else
a = x.y - y.y, b = y.x - x.x, c = x.x * y.y - y.x * x.y;
}
void PlumbLine(poi x, poi y)//中垂线
{
poi mx = (x + y) / 2;
this->s.x = mx.x - (x.y - mx.y); this->s.y = mx.y + (x.x - mx.x);
this->t.x = mx.x - (y.y - mx.y); this->t.y = mx.y + (y.x - mx.x);
this->ang = (t - s).X_ang();
if (fabs(s.x - t.x) < eps)
a = 1, b = 0, c = -s.x;
else if (fabs(s.y - t.y) < eps)
a = 0, b = 1, c = -s.y;
else
a = s.y - t.y, b = t.x - s.x, c = s.x * t.y - t.x * s.y;
}
};
inline double DotMulti(poi x, poi y) { return x.x * y.x + x.y * y.y; }//点乘
inline double CrossMulti(poi x, poi y) { return x.x * y.y - x.y * y.x; }//叉乘
poi Base;//极角排序原点
bool comp1(poi x, poi y)//根据极角排序
{
if ((x - Base).Quadrant() ^ (y - Base).Quadrant())
return (x - Base).Quadrant() < (y - Base).Quadrant();
double z = CrossMulti(x - Base, y - Base);
if (fabs(z) < eps) return (x - Base).O_len() < (y - Base).O_len();
return z > 0;
}
bool comp2(poi x, poi y)//根据x,y坐标排序
{
if (x.x != y.x)
return x.x < y.x;
return x.y < y.y;
}
int ConvexHull(int l, poi o[], poi con[])//凸包
{
sort(o + 1, o + l + 1, comp2);
int i, k = 0;
for (i = 1; i <= l; i++)
{
for (; k > 1 && CrossMulti(con[k] - con[k - 1], o[i] - con[k - 1]) < 0; k--);
con[++k] = o[i];
}
int d = k;
for (i = l - 1; i; i--)
{
for (; k > d && CrossMulti(con[k] - con[k - 1], o[i] - con[k - 1]) < 0; k--);
con[++k] = o[i];
}
return k;
}
inline double pf(double x) { return x * x; }//平方
inline double dis(poi x, poi y) { return sqrt(pf(x.x - y.x) + pf(x.y - y.y)); }//两点距离
inline poi intersection(line x, line y) { return x.s + (x.t - x.s) * CrossMulti(x.s - y.s, y.t - y.s) / CrossMulti(y.t - y.s, x.t - x.s); }//两直线交点
inline poi Circumcir(poi x, poi y, poi z)//三点外接圆圆心
{
line Lxy, Lxz;
Lxy.PlumbLine(x, y); Lxz.PlumbLine(x, z);
return intersection(Lxy, Lxz);
}
void MinCir(poi& cir, double& r, poi o[], int n)//最小圆覆盖
{
random_shuffle(o + 1, o + n + 1);
cir = o[1]; r = 0;
for (int i = 1; i <= n; i++)
if (dis(o[i], cir) - r > eps)
{
cir = o[i]; r = 0;
for (int j = 1; j < i; j++)
if (dis(o[j], cir) - r > eps)
{
cir = (o[i] + o[j]) / 2;
r = dis(o[i], o[j]) / 2;
for (int k = 1; k < j; k++)
if (dis(o[k], cir) - r > eps)
{
cir = Circumcir(o[i], o[j], o[k]);
r = dis(o[i], cir);
}
}
}
}
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
int main()
{
int i, j, l, x, y, z, n, m, T;
return 0;
}
posted on 2018-11-05 19:15 Iowa_Battleship 阅读(492) 评论(1) 编辑 收藏 举报