一名苦逼的OIer,想成为ACMer

Iowa_Battleship

模板复习

没几天就要退役了\(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;
}
  • 扩展欧几里得
一直不太会这玩意,不会推又记不住结论。。只好在这写一遍结论了。 求方程$ax + by = c$的解$x, y$,设$d = \gcd(a, b)$,那么方程有解仅当$d | c$。 先用$exgcd$求出$ax + by = d$的特解$x_0, y_0$,那么原方程的特解为$\frac{c}{d}\times x_0, \frac{c}{d}\times y_0$。 而通解为$x = \frac{c}{d}\times x_0 + k \times \frac{b}{d}, y = \frac{c}{d}\times y_0 - k \times \frac{a}{d}, (k \in \mathbb{Z})$。 求线性同余方程$a \times x \equiv b\ (mod\ m)$的解。 设$a \times x - b$为$m$的$-y$倍,那么方程转化为$a \times x + m \times y = b$,于是同样可以和上面一样解出特解$x_0$,那么原方程的一个解为$x_0 \times \frac{b}{\gcd(a, m)}$,通解为所有模$\frac{m}{\gcd(a, m)}$与$x$同余的整数。

模板传送门
并没有找到什么好的模板,只好用这道\(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;
}
  • 堆(二叉堆,STL优先队列)
    只会用STL
    模板传送门
#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;
}
  • SPFA
    模板传送门
    关于SPFA,他已经死了,让我们挂一张遗像
#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;
}
  • DFS
    模板传送门
    注意有负边权时,DFS并不能跑出正确的直径。

#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编辑  收藏  举报

导航