将回忆酿成烈酒入喉 从此不再挽留不再回头 |

Altwilio

园龄:3年5个月粉丝:10关注:7

模板大全(转载)

模板

分类:    具体: 

最大公约数 (gcd) [#nt01]:

int gcd(int a, int b) {return b ? gcd(b, a % b) : a;}

快速幂 (递归版本) [#nt02]:

ll PowerMod(ll a, ll n, ll m = mod) {
	if (!n || a == 1) return 1ll;
	ll s = PowerMod(a, n >> 1, m);
	s = s * s % m;
	return n & 1 ? s * a % m : s;
}

快速幂 (非递归版本) [#nt03]:

ll PowerMod(ll a, int n, ll c = 1) {for (; n; n >>= 1, a = a * a % mod) if (n & 1) c = c * a % mod; return c;}

扩展 Euclid 算法 (exgcd) [#nt04]:

ll exgcd(ll a, ll b, ll &x, ll &y) {
	if (b) {ll d = exgcd(b, a % b, y, x); return y -= a / b * x, d;}
	else return x = 1, y = 0, a;
}

基本预处理 [#nt05]:

// factorials, fact-inverses, unbounded
void init() {
	int i;
	for (*fact = i = 1; i < N; ++i) fact[i] = (ll)fact[i - 1] * i % mod;
	--i, finv[i] = PowerMod(fact[i], mod - 2);
	for (; i; --i) finv[i - 1] = (ll)finv[i] * i % mod;
}

// factorials, fact-inverses, bounded
void init(int n) {
	int i;
	for (*fact = i = 1; i <= n; ++i) fact[i] = (ll)fact[i - 1] * i % mod;
	finv[n] = PowerMod(fact[n], mod - 2);
	for (i = n; i; --i) finv[i - 1] = (ll)finv[i] * i % mod;
}

// inverses, factorials, fact-inverses, unbounded
void init() {
	int i;
	for (inv[1] = 1, i = 2; i < N; ++i) inv[i] = ll(mod - mod / i) * inv[mod % i] % mod;
	for (*finv = *fact = i = 1; i < N; ++i) fact[i] = (ll)fact[i - 1] * i % mod, finv[i] = (ll)finv[i - 1] * inv[i] % mod;
}

// inverses, factorials, fact-inverses, bounded
void init(int n) {
	int i;
	for (inv[1] = 1, i = 2; i <= n; ++i) inv[i] = ll(mod - mod / i) * inv[mod % i] % mod;
	for (*finv = *fact = i = 1; i <= n; ++i) fact[i] = (ll)fact[i - 1] * i % mod, finv[i] = (ll)finv[i - 1] * inv[i] % mod;
}

线性筛素数 (筛最小素因子) [#nt06]:

int pn = 0, c[N], p[78540];

void sieve(int n) {
	int i, j, v;
	memset(c, -1, sizeof c);
	for (i = 2; i <= n; ++i) {
		if (!~c[i]) p[pn] = i, c[i] = pn++;
		for (j = 0; (v = i * p[j]) <= n && j <= c[i]; ++j) c[v] = j;
	}
}

Miller-Rabin 素数测试 [#nt07]:

// No pseudoprime below 2^64 to base 2, 3, 5, 7, 11, 13, 82, 373.
const int test[8] = {2, 3, 5, 7, 11, 13, 82, 373};
bool Miller_Rabin(ll n) {
	if (n < MAX) return !c[n] && n > 1;
	int c, i, j; ll s = n - 1, u, v;
	for (c = 0; !(s & 1); ++c, s >>= 1);
	for (i = 0; i < 8; ++i) {
		if (!(n % test[i])) return false;
		u = PowerMod(test[i], s, n);
		for (j = 0; j < c; ++j, u = v)
			if (v = MulMod(u, u, n), u != 1 && u != n - 1 && v == 1) return false;
		if (u != 1) return false;
	}
	return true;
}

分解质因数 [#nt08]:

// version 1
inline void push(ll prime, int alpha) {pr[cnt] = prime, al[cnt++] = alpha;}

// version 2
inline void push(ll prime, int alpha) {
	map::iterator it = result.find(prime);
	it == result.end() ? (void)result.emplace(prime, alpha) : (void)(it->second += alpha);
}

void factor(ll n) {
	int i, j; cnt = 0; // result.clear();
	for (i = 0; n > 1; ) {
		if (n >= N) {
			for (; (ll)p[i] * p[i] <= n && n % p[i]; ++i);
			if (n % p[i]) return push(n, 1);
		} else i = c[n];
		for (j = 0; !(n % p[i]); n /= p[i], ++j); push(p[i], j);
	}
}

线性筛 Euler φ 函数 [#nt09]:

void sieve(int n) {
	int i, j, v; phi[1] = 1;
	memset(c, -1, sizeof c);
	for (i = 2; i <= n; ++i) {
		if (!~c[i]) p[pn] = i, c[i] = pn++, phi[i] = i - 1;
		for (j = 0; (v = i * p[j]) <= n && j < c[i]; ++j) c[v] = j, phi[v] = phi[i] * (p[j] - 1);
		if (v <= n) c[v] = j, phi[v] = phi[i] * p[j];
	}
}

线性筛 Möbius μ 函数 [#nt10]:

void sieve(int n) {
	int i, j, v; mu[1] = 1;
	memset(c, -1, sizeof c);
	for (i = 2; i <= n; ++i) {
		if (!~c[i]) p[pn] = i, c[i] = pn++, mu[i] = -1;
		for (j = 0; (v = i * p[j]) <= n && j < c[i]; ++j) c[v] = j, mu[v] = -mu[i];
		if (v <= n) c[v] = j;
	}
}

遍历 ⌊n / i⌋ 的所有可能值 (旧版整除分块) [#nt11]:

#define next(n, i) (n / (n / i + 1))
for(i = n; i >= 1; i = j){
	j = next(n, i);
	// do something
}

#define _next(n, i) (n / (n / (i + 1)))
for(i = 0; i < n; i = j){
	j = _next(n, i);
	// do something
}

// 0 1 100 1 2 50 2 3 33 3 4 25 4 5 20 5 6 16 16 6 7 14 7 8 12 8 9 11 9 10 10 10 11 9 11 12 8 12 13 7 14 15 6 16 17 5 20 21 4 25 26 3 33 34 2 50 51 1 100 101 0 ?

新版整除分块 [#nt12]:

// int32 ver.
int n, cnt, srn;
int v[G];

inline int ID(int x) {return x <= srn ? x : cnt + 1 - n / x;}

{
	int i;
	srn = sqrt(n), cnt = srn * 2 - (srn * (srn + 1) > n);
	for (i = 1; i <= srn; ++i) v[i] = i, v[cnt - i + 1] = n / i;
}

// int64 ver.
ll n, v[G];
int cnt, srn;

inline int ID(ll x) {return x <= srn ? x : cnt + 1 - n / x;}

{
	int i;
	srn = sqrt(n), cnt = srn * 2 - (srn * (srn + 1ll) > n);
	for (i = 1; i <= srn; ++i) v[i] = i, v[cnt - i + 1] = n / i;
}

杜氏求和法 / 杜教筛 [#nt13]:

void Dsum() {
	int i, j, k, l, n, sq, _;
	for (i = 1; i <= cnt && v[i] < N; ++i) Mu[i] = smu[v[i]], Phi[i] = sphi[v[i]];
	for (; i <= cnt; ++i) {
		int &m = Mu[i]; ll &p = Phi[i];
		n = v[i], sq = sqrt(n), m = 1, p = n * (n + 1ll) / 2, l = n / (sq + 1);
		for (j = sq; j; --j) {
			_ = (k = n / j) - l, m -= _ * smu[j], p -= _ * sphi[j], l = k;
			if (j != 1 && k > sq) m -= Mu[_ = ID(k)], p -= Phi[_];
		}
	}
}

大小步离散对数 [#nt14]:

int Boy_Step_Girl_Step(){
	mii :: iterator it;
	ll boy = 1, girl = 1, i, t;
	for(i = 0; i < B; i++){
		m.insert(pr((int)boy, i)); // if there exists in map, then ignore it
		(boy *= a) %= p;
	}
	for(i = 0; i * B < p; i++){
		t = b * inv(girl) % p;
		it = m.find((int)t);
		if(it != m.end())
			return i * B + it->second;
		(girl *= boy) %= p;
	}
	return -1;
}

// input p and then B = (int)sqrt(p - 1);
// inv(x) is the multiplicative inverse of x in Z[p].
// mii: map <int, int> and m is a variable of which.

Pollard-Rho 素因数分解 [#nt15]:

ll Pollard_Rho(ll n, int c) {
	ll i = 1, k = 2, x = rand() % (n - 1) + 1, y = x, p;
	for (; k <= 131072; ) {
		x = (MulMod(x, x, n) + c) % n;
		p = gcd<ll>((ull)(y - x + n) % n, n);
		if (p != 1 && p != n) return p;
		if (++i == k) y = x, k <<= 1;
	}
	return 0;
}

inline void push(ll prime, int alpha) {
	map::iterator it = result.find(prime);
	it == result.end() ? (void)result.insert(pr(prime, alpha)) : (void)(it->second += alpha);
}

void factor(ll n) {
	int i, j, k; ll p;
	for (i = 0; n != 1; )
		if (n >= MAX) {
			if (Miller_Rabin(n)) {push(n, 1); return;}
			for (k = 97; !(p = Pollard_Rho(n, k)); --k);
			factor(p); n /= p;
		} else {
			i = (c[n] ? c[n] : n);
			for (j = 0; !(n % i); n /= i, ++j);
			push(i, j);
		}
}

字符串 Hash [#str01]:

const ll mod[3] = {900000011, 998244353, 1000000007};
const ll bas[3] = {4493, 8111, 8527};
// you can choose your bases and modulos

char s[S];
ll pw[3][S], Hash[3][S];

inline ll getHash(int id, int L, int R){ // str[L..R-1]
	ll J = (Hash[id][R] - Hash[id][L] * pw[id][R - L]) % mod[id];
	return J < 0 ? J + mod[id] : J;
}

// following is the pretreatment
ll *f, *g;
for(j = 0; j < 3; j++){
	f = Hash[j]; f[0] = 0;
	g = pw[j]; g[0] = 1;
	for(i = 0; i < n; i++){
		f[i + 1] = (f[i] * bas[j] + (s[i] - 'a')) % mod[j];
		g[i + 1] = g[i] * bas[j] % mod[j];
	}
}

KMP 模式匹配 [#str02]:

// pretreatment (border) 
for (j = *f = -1, i = 1; i < n; f[++i] = ++j)
	for (; ~j && s[j] != s[i]; j = f[j]);

// KMP
for (j = i = 0; i < _n; ++i) {
	for (; ~j && s[j] != m[i]; j = f[j]);
	if (++j == n) printf("%d ", i - s_n + 2);
}

字典树 [#str03]:

void append(char *s){
	char *p = s;
	int t = 1, id; // t = 0 is also OK
	for(; *p; ++p){
		id = *p - 97;
		t = d[t][id] ? d[t][id] : (d[t][id] = ++V);
	}
	++val[t];
}

// the process of matching is just like going on a DFA, so omit it.

Aho-Corasick 自动机 [#str04]:

void build(){
	int h, ta = 1, i, t, id;
	que[0] = 1;
	f[1] = 0;
	for(h = 0; h < ta; ++h)
		for(i = que[h], id = 0; id < 26; ++id){ // 26 is the size of char-set
			t = (f[i] ? d[f[i]][id] : 1); // 1 or 0 depend on the root of trie
			int &u = d[i][id];
			if(!u) {u = t; continue;}
			f[u] = t; val[u] |= val[t]; que[ta++] = u;
			la[u] = (v[t] ? t : la[t]);
		}
}

后缀数组 (倍增构造) 与最长公共前缀 [#str05]:

struct LCP {
	int n, *sa, *rnk, *st[LN];
	LCP () : n(0), sa(NULL), rnk(NULL) {memset(st, 0, sizeof st);}
	~LCP () {
		if (sa) delete [] sa;
		if (rnk) delete [] rnk;
		for (int i = 0; i < LN; ++i) if (st[i]) delete [] st[i];
	}
	void construct(const char *s) {
		int i, j, k, m = 256, p, limit; n = strlen(s);
		int *x = new int[n + 1], *y = new int[n + 1], *buf = new int[max(n, m)], *f, *g = new int[n + 1];
		auto cmp = [this] (const int *a, const int u, const int v, const int l) {return a[u] == a[v] && (u + l >= n ? 0 : a[u + l]) == (v + l >= n ? 0 : a[v + l]);};
		if (sa) delete [] sa; sa = new int[n];
		if (rnk) delete [] rnk;
		for (i = 0; i < LN; ++i) if (st[i]) delete [] st[i], st[i] = 0;
		for (i = 0; i < n; ++i) sa[i] = i, x[i] = (unsigned char)s[i];
		std::sort(sa, sa + n, [s] (const int u, const int v) {return (unsigned char)s[u] < (unsigned char)s[v];});
		for (j = 1; j < n; j <<= 1, m = ++p) {
			std::iota(y, y + j, n - j), p = j;
			for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
			memset(buf, 0, m << 2);
			for (i = 0; i < n; ++i) ++buf[ x[y[i]] ];
			for (i = 1; i < m; ++i) buf[i] += buf[i - 1];
			for (i = n - 1; i >= 0; --i) sa[ --buf[ x[y[i]] ] ] = y[i];
			std::swap(x, y);
			x[*sa] = p = 1, x[n] = 0;
			for (i = 1; i < n; ++i) x[sa[i]] = (cmp(y, sa[i - 1], sa[i], j) ? p : ++p);
			if (p >= n) break;
		}
		if (rnk = x, n == 1) *x = 0;
		else for (i = 0; i < n; ++i) --x[i];
		delete [] buf, delete [] y;
		for (p = i = 0; i < n; ++i) {
			if (p && --p, !x[i]) continue;
			for (j = sa[x[i] - 1], limit = n - max(i, j); p < limit && s[i + p] == s[j + p]; ++p);
			g[ x[i] - 1 ] = p;
		}
		*st = g, k = n - 1;
		for (j = 0; 1 << (j + 1) < n; ++j) {
			k -= 1 << j, f = g, g = st[j + 1] = new int[k + 1];
			for (i = 0; i < k; ++i)
				g[i] = min(f[i], f[i + (1 << j)]);
		}
	}
	inline int operator () (const int u, const int v) {
		assert((unsigned)u < (unsigned)n && (unsigned)v < (unsigned)n);
		if (u == v) return n - u;
		int L, R, c; std::tie(L, R) = std::minmax(rnk[u], rnk[v]), c = lg2(R - L);
		return min(st[c][L], st[c][R - (1 << c)]);
	}
};

后缀自动机 [#str06]:

#define q d[p][x]
int extend(int x) {
	for (p = np, val[np = ++cnt] = val[p] + 1; p && !q; q = np, p = pa[p]);
	if (!p) pa[np] = 1;
	else if (val[p] + 1 == val[q]) pa[np] = q;
	else {
		int nq = ++cnt;
		val[nq] = val[p] + 1, memcpy(d[nq], d[q], 104);
		pa[nq] = pa[q], pa[np] = pa[q] = nq;
		for (int Q = q; p && q == Q; q = nq, p = pa[p]);
	}
	return f[np] = 1, np;
}
#undef q

根据后缀自动机构造后缀树 [#str07]:

void build() {
	int i, j, c; used[1] = true;
	for (i = cnt; i; --i) if (~pos[i])
		for (j = i; !used[j]; j = pa[j])
			c = pos[j] - val[pa[j]], pos[pa[j]] = pos[j],
			child[pa[j]][int(s[c])] = j, used[j] = true;
//	dfs(1);
}

Z 算法 [#str08]:

void Z() {
	int i, Max = 0, M = 0;
	for (i = 1; i < n; ++i) {
		z[i] = (i < Max ? std::min(z[i - M], Max - i) : 0);
		for (; s[z[i]] == s[i + z[i]]; ++z[i]);
		if (i + z[i] > Max) Max = i + z[i], M = i;
	}
}

Manacher 回文串 [#str09]:

void Manacher() {
	int n = 2, i, Max = 0, M = 0;
	t[0] = 2, t[1] = 1;
	for (i = 0; i < S; ++i) t[n++] = s[i], t[n++] = 1; t[n++] = 3;
	for (i = 0; i < n; ++i){
		f[i] = (i < Max ? std::min(f[M * 2 - i], Max - i) : 1);
		for(; t[i + f[i]] == t[i - f[i]]; ++f[i]);
		if (i + f[i] > Max) Max = i + f[i], M = i;
	}
}

回文自动机 [#str10]:

int get_fail(int x) {for (; ptr[~val[x]] != *ptr; x = fail[x]); return x;}

int extend(int x) {
	int &q = d[p = get_fail(p)][x];
	if (!q) fail[++cnt] = d[get_fail(fail[p])][x], val[q = cnt] = val[p] + 2;
	return p = q;
}

val[1] = -1, p = 0, *fail = cnt = 1;

多串后缀自动机 / 广义后缀自动机 [#str11]:

#define q d[p][x]
#define try_split(v) { \
	if (val[p] + 1 == val[q]) v = q; \
	else { \
		int nq = ++cnt; \
		val[nq] = val[p] + 1, memcpy(d[nq], d[q], 104); \
		pa[nq] = pa[q], v = pa[q] = nq; \
		for (int Q = q; p && q == Q; q = nq, p = pa[p]); \
	} \
}

int extend(int x) {
	if (p = np, q) try_split(np)
	else {
		for (val[np = ++cnt] = val[p] + 1; p && !q; q = np, p = pa[p]);
		if (p) try_split(pa[np]) else pa[np] = 1;
	}
	return np;
}
#undef q

深度优先搜索,dfs 序,树上基本操作 [#tr01]:

void dfs(int x) {
	int i, y; o[++cnt] = x, id[x] = cnt, size[x] = 1;
	for (i = first[x]; i; i = next[i])
		if ((y = to[i]) != p[x])
			p[y] = x, dep[y] = dep[x] + 1, dfs(y), size[x] += size[y];
	eid[x] = cnt;
}

最近公共祖先 (LCA) 的倍增算法 (树上倍增的基本模板) [#tr02]:

void dfs(int x) {
	int i, y;
	for (i = 0; P[i][x]; ++i) P[i + 1][x] = P[i][P[i][x]];
	for (i = first[x]; i; i = next[i])
		if ((y = to[i]) != p[x])
			p[y] = x, dep[y] = dep[x] + 1, dfs(y);
}

int jump_until(int x, int d) {
	for (int S = dep[x] - d; S; S &= S - 1) x = P[ctz(S)][x];
	return x;
}

int LCA(int x, int y) {
	if (dep[x] < dep[y]) std::swap(x, y);
	if (x = jump_until(x, dep[y]), x == y) return x;
	for (int i = LN - 1; i >= 0; --i)
		if (P[i][x] != P[i][y])
			x = P[i][x], y = P[i][y];
	return p[x];
}

最近公共祖先 (LCA) 的 ST 表算法 [#tr03]:

int cnt = 0, id[N], o[N], st[LN][N];

void dfs(int x, int px = 0) {
	int i, y; st[0][cnt] = id[px], o[++cnt] = x, id[x] = cnt;
	for (i = first[x]; i; i = next[i])
		if ((y = to[i]) != px) dfs(y, x);
}

void build_sparse_table() {
	int *f, *g = *st, i, j, k = n - 1;
	for (j = 0; 1 << (j + 1) < n; ++j) {
		f = g, g = st[j + 1], k -= 1 << j;
		for (i = 1; i <= k; ++i)
			g[i] = min(f[i], f[i + (1 << j)]);
	}
}

inline int LCA_relabel(int x, int y) {
	if (x == y) return x;
	if (x > y) std::swap(x, y);
	int c = lg2(y - x);
	return min(st[c][x], st[c][y - (1 << c)]);
}

inline int LCA(int x, int y) {
	if (x == y) return x;
	int L, R, c; std::tie(L, R) = std::minmax(id[x], id[y]), c = lg2(R - L);
	return o[min(st[c][L], st[c][R - (1 << c)])];
}

轻重链剖分 (Heavy-Light Decomposition) [#tr04]:

int p[N], dep[N], size[N];
int cnt = 0, id[N], prf[N], top[N];

void dfs_wt(int x) {
	int i, y, &z = prf[x]; size[x] = !next[first[x]];
	for (i = first[x]; i; i = next[i])
		if ((y = to[i]) != p[x]) {
			p[y] = x, dep[y] = dep[x] + 1;
			dfs_wt(y), size[x] += size[y];
			size[y] > size[z] ? z = y : 0;
		}
}

void dfs_hld(int x, int r) {
	int i, y; id[x] = ++cnt, top[x] = r;
	if (!prf[x]) return;
	dfs_hld(prf[x], r);
	for (i = first[x]; i; i = next[i])
		if (!top[y = to[i]]) dfs_hld(y, y);
}

int solve(int u, int v) {
	int x = top[u], y = top[v];
	for (; x != y; u = p[x], x = top[u]) {
		if (dep[x] < dep[y]) {swap(u, v); swap(x, y);}
		// do something on [x, u]
	}
	if (dep[u] > dep[v]) {swap(u, v); swap(lx, ly);}
	// do something on [u, v]
	// return something
}

树分治 (静态点分治) [#tr05]:

namespace Centroid {
	int V, Gm, G, size[N];

	void init(int _V) {V = _V, Gm = INT_MAX;}

	int get(int x, int px = 0) {
		int i, y, M = 0; size[x] = 1;
		for (i = first[x]; i; i = next[i])
			if ((y = to[i]) != px && !banned[y])
				get(y, x), up(M, size[y]), size[x] += size[y];
		return up(M, V - size[x]), M <= Gm ? (Gm = M, G = x) : G;
	}
}

#define get_centroid(x, y) (Centroid::init(y), Centroid::get(x))

void dfs(int x, int px = 0, int dep = 1) {
	int i, y; size[x] = 1;
	for (i = first[x]; i; i = next[i])
		if ((y = to[i]) != px && !banned[y])
			dfs(y, x, dep + 1), size[x] += size[y];
}

void solve(int x) {
	int i, y, G;
	banned[x] = true, dfs(x);
	// do something
	for (i = first[x]; i; i = next[i])
		if (!fy[y = to[i]])
			G = get_centroid(y, size[y]), solve(G);
}

// main
G = get_centroid(1, n), solve(G);

虚树 (深度栈算法) [#tr06]:

int cnt_vir, vir[N], virp[N];

inline bool idcmp(const int x, const int y) {return id[x] < id[y];}

void DSA(int n, int *v) {
	#define ins(x) (virp[x] = stack[top], stack[++top] = vir[cnt_vir++] = x)
	int i, x, y, top = 0; cnt_vir = 0;
	for (i = 0; i < n; ++i)
		if (x = v[i], !top) {
			for (; top; --top) stack[top] = 0; ins(x);
		} else {
			stack[top + 1] = 0;
			for (y = LCA(x, stack[top]); dep[ stack[top] ] > dep[y]; --top);
			virp[ stack[top + 1] ] = y;
			if (stack[top] != y) ins(y); ins(x);
		}
	for (; top; --top) stack[top] = 0;
	std::sort(vir, vir + cnt_vir, idcmp);
}

长链剖分 (Long-Short Decomposition) [#tr07]:

int p[N], dep[N], f[N];
int cnt = 0, id[N], prf[N], top[N];
int len[N], buf[N * 3], *alloc = buf, *near[N];

void dfs_len(int x) {
	int i, y, &z = prf[x];
	for (i = 0; i < LN && P[i][x]; ++i) P[i + 1][x] = P[i][P[i][x]];
	for (i = first[x]; i; i = next[i])
		if ((y = to[i]) != p[x]) {
			p[y] = x, dep[y] = dep[x] + 1;
			dfs_len(y), up(f[x], f[y] + 1);
			f[y] > f[z] ? z = y : 0;
		}
}

void dfs_lsd(int x, int r, int l = 1) { // long-short decomposition
	int i, y; id[x] = ++cnt, top[x] = r;
	if (!prf[x]) {len[x] = l; return;}
	dfs_lsd(prf[x], r, l + 1), len[x] = len[prf[x]];
	for (i = first[x]; i; i = next[i])
		if (!top[y = to[i]]) dfs_lsd(y, y);
}

int ancestor(int x, int k) {
	if (dep[x] < k) return 0;
	if (!k) return x;
	x = P[i][x], near[top[x]][dep[x] - dep[top[x]] - (k - (1 << lg2(k)))];
}

void init() {
	int i, j, x, *pt;
	*f = *dep = -1, dfs_len(1), dfs_lsd(1, 1);
	for (i = 1; i < N; ++i)
		if (top[i] == i) {
			pt = alloc + len[i], alloc += len[i] * 2 + 1, *pt = i;
			for (j = 1, x = p[i]; j <= len[i] && x; ++j, x = p[x]) pt[-j] = x;
			for (j = 1, x = prf[i]; j <= len[i] && x; ++j, x = prf[x]) pt[j] = x;
		}
}

双向邻接表 [#gr01]:

inline void addedge(int u, int v) {
	to[++E] = v, next[E] = first[u], first[u] = E;
	to[++E] = u, next[E] = first[v], first[v] = E;
}

有向图的强连通分量 [#gr02]:

void dfs(int x) {
	int i, y;
	id[x] = low[x] = ++cnt, instack[x] = true, sta[stc++] = x;
	for(i = first[x]; i; i = next[i])
		if (!id[y = to[i]])
			dfs(y), down(low[x], low[y]);
		else if (instack[y])
			down(low[x], id[y]);
	if (id[x] == low[x])
		for (y = 0; y != x; )
			y = sta[--stc], instack[y] = false, top[y] = x;
}

有向无环图的拓扑排序 [#gr03]:

void toposort() {
	int i, h, t = 0, x, y;
	for (i = 1; i <= V; ++i) if (!deg[i]) que[t++] = i;
	for (h = 0; h < t; ++h)
		for (i = first[x = que[h]]; i; i = next[i])
			if (!--deg[y = to[i]]) que[t++] = y;
}

无向图的桥边 [#gr04]:

void dfs(int x, int px = 0) {
	int i, y;
	id[x] = low[x] = ++cnt;
	for (i = first[x]; i; i = next[i])
		if (!id[y = to[i]]) {
			dfs(y, i), down(low[x], low[y]);
			if (id[x] < low[y]) // edge i is a bridge
		} else if (px - 1 ^ i - 1 ^ 1)
			down(low[x], id[y]);
}

无向图的割点 [#gr05]:

void dfs(int x, int px = 0) {
	int i, y, c = 0; bool is_cut = false;
	id[x] = low[x] = ++cnt;
	for (i = first[x]; i; i = next[i])
		if (!id[y = to[i]]) {
			dfs(y, i), down(low[x], low[y]), ++c;
			if (id[x] <= low[y]) is_cut = true;
		} else if (px - 1 ^ i - 1 ^ 1)
			down(low[x], id[y]);
	if (!px) is_cut = c > 1;
}

无向图的边双缩点 [#gr06]:

void dfs(int x, int px = 0) {
	int i, y;
	id[x] = low[x] = ++cnt, stack[stc++] = x;
	for (i = first[x]; i; i = next[i])
		if (!id[y = to[i]]) {
			dfs(y, i), down(low[x], low[y]);
			if (id[x] < low[y]) bridge[ad(i)] = bridge[i] = true;
		} else if (px - 1 ^ i - 1 ^ 1)
			down(low[x], id[y]);
	if (id[x] == low[x])
		for (y = 0; y != x; )
			y = stack[--stc], top[y] = x;
}

无向图的点双缩点 / 圆方树 [#gr07]:

void dfs(int x, int px = 0) {
	int i, y, z;
	id[x] = low[x] = ++cnt, stack[top++] = x;
	for (i = first[x]; i; i = next[i])
		if (!id[y = to[i]]) {
			dfs(y, i), down(low[x], low[y]);
			if (id[x] <= low[y])
				for (link(++bcc_cnt + V, x), z = 0; z != y; )
					link(z = stack[--top], bcc_cnt + V);
		} else if (px - 1 ^ i - 1 ^ 1)
			down(low[x], id[y]);
}

带权 edge 结构体 [#gr08]:

struct edge {
	int u, v, w;
	edge (int u0 = 0, int v0 = 0, int w0 = 0) : u(u0), v(v0), w(w0) {}
};

单源最短路 (Dijkstra) [#gr09]:

typedef std::pair <int, int> pr;

int d[N];
std::priority_queue <pr, std::vector <pr>, std::greater <pr>> pq;

void Dijkstra(int s) {
	int i, x, y, D;
	memset(d, 63, (V + 1) << 2);
	for (pq.emplace(d[s] = 0, s); !pq.empty(); ) {
		std::tie(D, x) = pq.top(), pq.pop();
		if (d[x] != D) continue;
		for (i = first[x]; i; i = next[i])
			if (D + e[i].w < d[y = e[i].v])
				pq.emplace(d[y] = D + e[i].w, y);
	}
}

所有点对的最短路 (Floyd) [#gr10]:

void Floyd() {
	int i, j, k;
	for (k = 1; k <= V; ++k)
		for (i = 1; i <= V; ++i)
			for (j = 1; j <= V; ++j)
				down(d[i][j], d[i][k] + d[k][j]);
}

最小生成树 (Kruskal) [#gr11]:

struct edge {
	int u, v, w;
	edge (int u0 = 0, int v0 = 0, int w0 = 0): u(u0), v(v0), w(w0) {}
	bool operator < (const edge &b) const {return w < b.w;}
};

void Kruskal(){
	uf.resize(V);
	sort(e + 1, e + (E + 1));
	for(i = 1; i <= E; i++)
		if(!uf.test(e[i].u, e[i].v, true)){
			// e is an edge of minimum spanning tree
			if(++Es >= V - 1) return;
		}
}

网络流 edge 结构体 [#gr12]:

struct edge {
	int u, v, f; // f is remaining flow
	edge(int u0 = 0, int v0 = 0, int f0 = 0): u(u0), v(v0), f(f0) {}
};

最大流 (Dinic) [#gr13]:

namespace Flow {
	#define ad(x) ((x - 1 ^ 1) + 1)

	const int N = 2000, M = 100000;

	struct edge {
		int u, v, f;
		edge (int u0 = 0, int v0 = 0, int f0 = 0) : u(u0), v(v0), f(f0) {}
	} e[M];

	int V = 2, E = 0, si = 1, ti = 2, flow;
	int first[N], next[M];
	int dep[N], cur[N], que[N];

	inline void addedge(int u, int v, int f) {
		e[++E] = edge(u, v, f), next[E] = first[u], first[u] = E;
		e[++E] = edge(v, u), next[E] = first[v], first[v] = E;
	}

	bool bfs() {
		int h, t = 1, i, x, y;
		memset(dep, -1, sizeof dep);
		que[0] = si, dep[si] = 0;
		for (h = 0; h < t; ++h) {
			if ((x = que[h]) == ti) return true;
			for (i = first[x]; i; i = next[i])
				if (dep[y = e[i].v] == -1 && e[i].f)
					que[t++] = y, dep[y] = dep[x] + 1;
		}
		return false;
	}

	int dfs(int x, int lim) {
		int a, c, f = 0;
		if (x == ti || !lim) return lim;
		for (int &i = cur[x]; i; i = next[i])
			if (dep[e[i].v] == dep[x] + 1 && e[i].f) {
				a = std::min(lim - f, e[i].f);
				c = dfs(e[i].v, a);
				e[i].f -= c, e[ad(i)].f += c;
				if ((f += c) == lim) return f;
			}
		return f;
	}

	int Dinic() {
		for (flow = 0; bfs(); flow += dfs(si, INT_MAX))
			memcpy(cur, first, sizeof cur);
		return flow;
	}
}

最小费用最大流 (Dinic) [#gr14]:

namespace CF {
	#define ad(x) ((x - 1 ^ 1) + 1)

	const int N = 2000, M = 100000, INF = 0x7f7f7f7f;

	struct edge {
		int u, v, c, f;
		edge (int u0 = 0, int v0 = 0, int c0 = 0, int f0 = 0) : u(u0), v(v0), c(c0), f(f0) {}
	} e[M];

	int V = 2, E = 0, si = 1, ti = 2, flow, cost;
	int first[N], next[M];
	int dep[N], cur[N], que[M << 1];
	bool in_que[N], used[N];

	inline void addedge(int u, int v, int c, int f) {
		e[++E] = edge(u, v, c, f), next[E] = first[u], first[u] = E;
		e[++E] = edge(v, u, -c), next[E] = first[v], first[v] = E;
	}

	bool bfs() {
		int h = M, t = h + 1, i, x, y;
		memset(dep, 127, sizeof dep);
		que[h] = ti, dep[ti] = 0, in_que[ti] = true;
		for (; h < t; ) {
			x = que[h++], in_que[x] = false;
			for (i = first[x]; i; i = next[i])
				if (dep[y = e[i].v] > dep[x] - e[i].c && e[ad(i)].f) {
					dep[y] = dep[x] - e[i].c;
					if (!in_que[y])
						in_que[y] = true, (dep[y] >= dep[que[h]] ? que[t++] : que[--h]) = y;
				}
		}
		return dep[si] < INF;
	}

	int dfs(int x, int lim) {
		int a, c, f = 0;
		if (x == ti || !lim) return lim;
		used[x] = true;
		for (int &i = cur[x]; i; i = next[i])
			if (dep[e[i].v] == dep[x] - e[i].c && e[i].f && !used[e[i].v]) {
				a = std::min(lim - f, e[i].f);
				c = dfs(e[i].v, a);
				e[i].f -= c, e[ad(i)].f += c;
				if ((f += c) == lim) return f;
			}
		return f;
	}

	int Dinic() {
		int f;
		for (cost = flow = 0; bfs(); ) {
			memcpy(cur, first, sizeof cur);
			memset(used, 0, sizeof used);
			flow += f = dfs(si, INF);
			cost += dep[si] * f;
		}
		return cost;
	}
}

二分图最大匹配 (增广路算法) [#gr15]:

bool dfs(int x){
	for(int i = 1; i <= n_g; i++)
		if(e[x][i] && !used[i]){
			used[i] = 1;
			if(!boy[i] || dfs(boy[i])){
				boy[i] = x; girl[x] = i; return true;
			}
		}
	return false;
}

一般图最大匹配 (带花树算法) [#gr16]:

#define unknown -1
#define boy 0
#define girl 1

int LCA(int x, int y) {
	for (++hash_cnt; x; y ? swap(x, y) : (void)0) {
		x = ancestor(x);
		if (hash[x] == hash_cnt) return x; // visited
		hash[x] = hash_cnt;
		x = prev[match[x]];
	}
	return 0x131a371;
}

void blossom(int x, int y, int root, int &t) { // vertices in blossoms are all boys !
	for (int z; ancestor(x) != root; y = z, x = prev[y]) {
		prev[x] = y; z = match[x];
		if (col[z] == girl) que[t++] = z, col[z] = boy;
		if (ancestor(x) == x) p[x] = root;
		if (ancestor(z) == z) p[z] = root;
	}
}

bool bfs(int st) {
	int h, t = 1, i, x, y, b, g;
	que[0] = st; col[st] = boy;
	for (h = 0; h < t; ++h)
		for (i = first[x = que[h]]; i; i = next[i])
			if (col[y = to[i]] == unknown) { // common step
				prev[y] = x; col[y] = girl;
				if (!match[y]) { // augment (change mates) !!!
					for (g = y; g; swap(match[b], g))
						match[g] = b = prev[g];
					return true;
				}
				col[que[t++] = match[y]] = boy;
			} else if(col[y] == boy && ancestor(x) != ancestor(y)) { // flower !!!
				b = LCA(x, y); blossom(x, y, b, t); blossom(y, x, b, t);
			}
	return false;
}

// main process
for (i = 1; i <= V; ++i) {
	for (v = 1; v <= V; ++v) col[v] = unknown, p[v] = v;
	if (!match[i] && bfs(i)) ++ans;
}

最小树形图 (朱-刘-Edmonds) [#gr17]:

namespace DMST {
	const int N = 108, M = 10054, INF = 0x3f3f3f3f;

	int V, E, r;
	int p[N], best[N];
	int bel[N], used[N], cyc[N];
	int min[N], delta[M];
	bool ans[M];
	edge e[M];
	pr elim[N * M];

	inline void reset(int n, int root) {V = n, E = 0, r = root;}

	inline void link(int u, int v, int w) {e[E++] = edge(u, v, w);}

	int CLE() {
		int i, u, v, w, n, r, cnt, tot = 0, w0 = 0, w1 = 0;
		n = V, r = DMST::r, std::iota(bel, bel + (V + 1), 0);
		memset(ans, false, E), memset(delta, 0, E << 2);
		for (; ; n = cnt, r = cyc[r]) {
			memset(min, 63, (V + 1) << 2),
			memset(used, 0, (V + 1) << 2), used[r] = -1;
			memset(cyc, cnt = 0, (V + 1) << 2);
			for (i = 0; i < E; ++i) {
				u = bel[ e[i].u ], v = bel[ e[i].v ], w = e[i].w - delta[i];
				if (u != v && w < min[v]) p[v] = u, min[v] = w, best[v] = i;
			}
			for (i = 1; i <= n; ++i) if (i != r) {
				if (min[i] >= INF) return -1;
				for (u = i; !(u == r || used[u]); u = p[u]) used[u] = i;
				if (used[u] == i) {
					++cnt, v = u;
					do cyc[v] = cnt, v = p[v]; while (v != u);
				}
			}
			if (!(w = cnt)) break;
			for (i = 1; i <= n; ++i)
				if (cyc[i]) ans[ best[i] ] = true;
				else cyc[i] = ++cnt;
			for (i = 0; i < E; ++i) {
				u = bel[ e[i].u ], v = bel[ e[i].v ];
				if (cyc[u] != cyc[v])
					if (delta[i] += min[v], cyc[v] <= w)
						elim[tot++] = pr(best[v], i);
			}
			for (i = 1; i <= V; ++i) bel[i] = cyc[bel[i]];
		}
		for (i = 1; i <= n; ++i) if (i != r) ans[ best[i] ] = true;
		for (i = tot - 1; i >= 0; --i) if (ans[elim[i].second]) ans[elim[i].first] = false;
		for (i = 0; i < E; ++i) if (ans[i]) ++w0, w1 += e[i].w;
		return assert(w0 == V - 1), w1;
	}
}

并查集 (不封装,按秩合并) [#ds01]:

int ancestor(int x) {return p[x] == x ? x : (p[x] = ancestor(p[x]));}

bool test(int x, int y, bool un = false) {
	if ((x = ancestor(x)) == (y = ancestor(y))) return true;
	if (un) size[x] > size[y] ? std::swap(x, y) : (void)0, p[x] = y, size[y] += size[x];
	return false;
}

并查集 (封装) [#ds02]:

struct UFind{
	int sz, *p;
	UFind (): sz(0) {p = NULL;}
	~UFind () {if(p) delete [] (p);}
	void resize(int size){
		if(p) delete [] (p); p = new int[(sz = size) + 1];
		for(int i = 0; i <= sz; i++) p[i] = i;
	}
	int ancestor(int x) {return x == p[x] ? x : p[x] = ancestor(p[x]);}
	bool test(int x, int y, bool un = false){
		if((x = ancestor(x)) == (y = ancestor(y))) return true;
		if(un) p[x] = y; return false;
	}
};

树状数组 (不封装) [#ds03]:

#define lowbit(x) (x & -x)

int sum(int h){
	int s = 0;
	while(h){
		s += a[h];
		h -= lowbit(h);
	}
	return s;
}

int add(int h, int v){
	while(h <= n){
		a[h] += v;
		h += lowbit(h);
	}
	return v;
}

树状数组 (封装,可清空) [#ds04]:

struct BIT {
	#define lowbit(x) (x & -x)
	int n, ti, tag[N]; ll x[N];
	BIT () : ti(0) {}
	inline void resize(int size) {n = size;}
	inline void clear() {++ti;}
	inline ll & recover(int id) {return tag[id] == ti ? x[id] : (tag[id] = ti, x[id] = 0);}
	ll sum(int h) {ll s = 0; for (; h > 0; h -= lowbit(h)) s += recover(h); return s;}
	void add(int h, ll v) {for (; h <= n; h += lowbit(h)) recover(h) += v;}
};

线段树 (不封装) [#ds05]:

#define segc int M = L + R - 1 >> 1, lc = id << 1, rc = lc | 1

void add(int id, int L, int R, int h, int v){
	if(L == R) return void(st[id] += v);
	segc; h <= M ? add(lc, L, M, h, v) : add(rc, M + 1, R, h, v);
	x[id].v = x[lc].v + x[rc].v;
}

int range(int id, int L, int R, int ql, int qr){
	if(ql <= L && qr >= R) return st[id];
	segc, s = 0;
	if(ql <= M) s += range(lc, L, M, ql, min(qr, M));
	if(qr > M) s += range(rc, M + 1, R, max(ql, M + 1), qr);
	return s;
}

线段树 (封装) [#ds06]:

struct ST{
	#define segc int M = L + R - 1 >> 1, lc = id << 1, rc = lc | 1
	int sz;
	struct node {int v, f; bool zero;} *x;
	ST (): sz(0) {x = NULL;}
	~ST () {if(x) delete [] (x);}
	void resize(int size) {sz = size; int sz0 = sz << 3; if(x) delete [] (x);
		x = new node[sz0]; memset(x, 0, sz0 * sizeof(node));}

	void add(int h, int v) {add(1, 1, sz, h, v);}
	int range(int l, int r) {return query(1, 1, sz, l, r);}

	void add(int id, int L, int R, int h, int v){
		if(L == R) return void(x[id].v += v);
		segc; h <= M ? add(lc, L, M, h, v) : add(rc, M + 1, R, h, v);
		x[id].v = x[lc].v + x[rc].v;
	}

	int query(int id, int L, int R, int ql, int qr){
		if(ql <= L && R <= qr) return x[id].v;
		segc, s = 0;
		if(ql <= M) s += query(lc, L, M, ql, min(qr, M));
		if(qr > M) s += query(rc, M + 1, R, max(ql, M + 1), qr);
		return s;
	}
};

可持久化线段树 (add 操作) [#ds07]:

int add(int _id, int L, int R, int h, int v){
	int id = ++cnt; x[id] = x[_id]; x[id].v += v;
	if(L == R) return id;
	int M = L + R - 1 >> 1;
	if(h <= M) x[id].lc = add(x[id].lc, L, M, h, v);
	else x[id].rc = add(x[id].rc, M + 1, R, h, v);
	return id;
}

伸展树 (Splay) [#ds08]:

#define pa p[nd]
#define root nd[0].c[0]
struct node {int v, sz, p, c[2]; ll sum;} nd[N];

inline int dir(int x) {return x == x[nd].pa.c[1];}

inline void update(int x){
	x[nd].sz = x[nd].c[0][nd].sz + x[nd].c[1][nd].sz + 1;
	x[nd].sum = x[nd].c[0][nd].sum + x[nd].c[1][nd].sum + x[nd].v;
}

void rotate(int x){
	int y = x[nd].p, d = !dir(x);
	nd[y[nd].c[!d] = x[nd].c[d]].p = y;
	x[nd].p = y[nd].p;
	y[nd].pa.c[dir(y)] = x;
	nd[x[nd].c[d] = y].p = x;
	update(y);
}

void splay(int x, int g = 0){
	for(; x[nd].p != g; rotate(x))
		if(x[nd].pa.p != g) rotate(dir(x) ^ dir(x[nd].p) ? x : x[nd].p);
	update(x);
}

void insert(int x){
	int y = 0, d = 0;
	if(root) for(y = root; d = (val[x] < y[nd].v), y[nd].c[d]; y = y[nd].c[d]);
	y[nd].c[d] = x;
	nd[x].v = nd[x].sum = val[x]; nd[x].sz = 1; nd[x].p = y; nd[x].c[0] = nd[x].c[1] = 0;
	splay(x);
}

void erase(int x){
	if(x[nd].p) splay(x);
	if(!(x[nd].c[0] && x[nd].c[1])){
		int d = (x[nd].c[1] > 0);
		x[nd].c[d][nd].p = 0;
		root = x[nd].c[d];
	}else{
		int y;
		for(y = x[nd].c[1]; y[nd].c[0]; y = y[nd].c[0]);
		splay(y, x);
		nd[y[nd].c[0] = x[nd].c[0]].p = y;
		y[nd].p = 0; root = y;
		update(y);
	}
}

int kth(int x, int v){
	if(x[nd].sz < v) return -1;
	for(int j; ; ){
		j = x[nd].c[0][nd].sz;
		if(v == j + 1) return x;
		x = x[nd].c[v > j]; v > j ? (v -= j + 1) : v;
	}
}

动态树 (Link-Cut Tree) [#ds09]:

namespace LCT {
	#define pa p[nd]
	struct node {bool rev; int v, p, c[2];} nd[N];
	inline int dir(int x) {return !nd[x].p ? -1 : x == nd[x].pa.c[0] ? 0 : x == nd[x].pa.c[1] ? 1 : -1;}
	inline void set(int x, int px, int c) {if (nd[x].p = px, ~c) nd[px].c[c] = x;}
	inline void reverse(int x) {x && (std::swap(nd[x].c[0], nd[x].c[1]), nd[x].rev = !nd[x].rev);}
	void push_down(int x) {if (nd[x].rev) reverse(nd[x].c[0]), reverse(nd[x].c[1]), nd[x].rev = false;}
	void pull_down(int x) {if (~dir(x)) pull_down(nd[x].p); push_down(x);}
	inline void update(int x) {const int l = nd[x].c[0], r = nd[x].c[1]; nd[x].v = (l ? nd[l].v : 0) + (r ? nd[r].v : 0);}
	void rotate(int x) {int y = nd[x].p, d = !dir(x); set(nd[x].c[d], y, !d), set(x, nd[y].p, dir(y)), set(y, x, d);}
	void splay(int x) {for (pull_down(x); ~dir(x); rotate(x)) if (~dir(nd[x].p)) rotate(dir(x) ^ dir(nd[x].p) ? x : nd[x].p); update(x);}
	void access(int x) {for (int y = 0; x; y = x, x = nd[x].p) splay(x), nd[x].c[1] = y, update(x);}
	void make_root(int x) {access(x), splay(x), reverse(x);}
	int find_root(int x) {for (access(x), splay(x); push_down(x), nd[x].c[0]; x = nd[x].c[0]); return splay(x), x;}
	int split(int x, int y) {return make_root(x), access(y), splay(y), y;}
	void link(int x, int y) {make_root(x), nd[x].p = y;}
	void cut(int x, int y) {split(x, y), nd[x].p = nd[y].c[0] = 0, update(y);}
	void trylink(int x, int y) {x == y || (split(x, y), ~dir(x)) || (nd[x].p = y);}
	void trycut(int x, int y) {split(x, y), nd[y].c[0] == x && !nd[x].c[1] && (nd[x].p = nd[y].c[0] = 0, update(y), 0);}
}

树堆 (Treap) [#ds10]:

struct random_t{
	ull seed;
	static const ull multiplier = 0x5deece66dll;;
	static const ull addend = 0xbll;
	static const ull mask = 0xffffffffffffll;

	random_t () {char *x = new char; seed = (ull)x; delete x;}

	unsigned int next(){
		seed = (seed * multiplier + addend) & mask;
		return seed >> 16;
	}

	unsigned int next(unsigned int n){
		return n * (ull)next() >> 32;
	}
}rnd;

#define pa p[nd]
#define C(x) c[x][nd]
#define root nd[0].c[0]

struct node {int v, sz, pt; int c[2], p; unsigned priority;} nd[N];
int cnt = 0;

inline int dir(int x) {return x == nd[x].pa.c[1];}

inline void update(int x){
	nd[x].sz = nd[x].C(0).sz + nd[x].C(1).sz + nd[x].pt;
}

void rotate(int x){
	int y = nd[x].p, d = !dir(x);
	nd[nd[y].c[!d] = nd[x].c[d]].p = y;
	nd[x].p = nd[y].p;
	nd[y].pa.c[dir(y)] = x;
	nd[nd[x].c[d] = y].p = x;
	update(y); update(x);
}

void push_up(int x) {for(; x; x = nd[x].p) update(x);}

void rotation(int x) {for(; nd[x].p && nd[x].priority < nd[x].pa.priority; ) rotate(x);}

void insert(int v){
	int x = 0, y = 0, d = 0;
	if(root) for(y = root; nd[y].v != v && nd[y].c[d = v > nd[y].v]; y = nd[y].c[d]);
	if(nd[y].v == v) {++nd[y].pt; push_up(y); return;}
	nd[y].c[d] = x = ++cnt;
	nd[x].v = v; nd[x].sz = nd[x].pt = 1; nd[x].p = y; nd[x].c[0] = nd[x].c[1] = 0;
	nd[x].priority = rnd.next(); push_up(y);
	rotation(x);
}

void erase(int v){
	int x = 0, y = 0, d = 0;
	if(root) for(x = root; nd[x].v != v && nd[x].c[d = v > nd[x].v]; x = nd[x].c[d]);
	if(nd[x].v != v) return;
	if(nd[x].pt > 1) {--nd[x].pt; push_up(x); return;}
	for(; nd[x].c[0] && nd[x].c[1]; rotate(nd[x].c[d]))
		d = nd[x].C(0).priority > nd[x].C(1).priority;
	d = nd[x].c[1] > 0; y = nd[x].c[d];
	nd[y].p = nd[x].p; nd[x].pa.c[dir(x)] = y; push_up(nd[y].p);
}

int rank(int v){
	int x = 0, d = 0, k = 0;
	if(root) for(x = root; nd[x].v != v && nd[x].c[d = v > nd[x].v]; x = nd[x].c[d])
		if(d) k += nd[x].C(0).sz + nd[x].pt;
	if(nd[x].v != v) return -1;
	return k + nd[x].C(0).sz;
}

int kth(int k){
	int x = root;
	if(nd[x].sz < k) return -1;
	for(int j, z; ; ){
		j = nd[x].C(0).sz; z = nd[x].pt;
		if(j <= k && k < j + z) return x;
		x = nd[x].c[k > j]; k > j ? (k -= j + z) : k;
	}
}

int prev(int v){
	int x = 0, r = -1, d = 0;
	if(root) for(x = root; x; x = nd[x].c[d]) if(d = v > x[nd].v) up(r, nd[x].v); // too little
	return r;
}

int succ(int v){
	int x = 0, r = INT_MAX, d = 0;
	if(root) for(x = root; x; x = nd[x].c[d]) if(!(d = v >= x[nd].v)) down(r, nd[x].v); // too large
	return r;
}

析合树 (构造) [#ds11]:

int n, p[N];

namespace DCTree {
	typedef std::pair <int, int> pr;
	const int N = ::N * 2;

	enum type {leaf, disjunct, conjunct} I[N];

	pr st[20][N];
	int stack1[N], stack2[N], stack[N];
	int cnt, root, left[N], mid[N], right[N];

	inline void up(pr &x, const pr &y) {x.first > y.first ? x.first = y.first : 0, x.second < y.second ? x.second = y.second : 0;}

	void build_sparse_table() {
		int i, j, k = n; pr *f, *g = *st;
		for (j = 0; 1 << (j + 1) <= n; ++j) {
			f = g, g = st[j + 1], k -= 1 << j;
			for (i = 1; i <= k; ++i)
				up(g[i] = f[i], f[i + (1 << j)]);
		}
	}

	inline bool is_consecutive(int L, int R) {
		int c = lg2(R - L); pr ans = st[c][L]; up(ans, st[c][R - (1 << c)]);
		return ans.second - ans.first == R - L - 1;
	}

	namespace ST {
		#define segc int M = (L + R - 1) >> 1, lc = id << 1, rc = lc | 1
		struct node {int v, tag;} x[N * 4];

		void build(int id, int L, int R) {
			x[id].v = L, x[id].tag = 0;
			if (L == R) return;
			segc; build(lc, L, M), build(rc, M + 1, R);
		}

		void add(int id, int L, int R, int ql, int qr, int v) {
			if (ql <= L && R <= qr) {x[id].v += v, x[id].tag += v; return;}
			segc;
			if (ql <= M) add(lc, L, M, ql, qr, v);
			if (qr > M) add(rc, M + 1, R, ql, qr, v);
			x[id].v = std::min(x[lc].v, x[rc].v) + x[id].tag;
		}

		int find_suf(int id, int L, int R, int v, int cv = 0) {
			if (cv + x[id].v > v) return -1;
			if (L == R) return L;
			segc, p = find_suf(lc, L, M, v, cv += x[id].tag);
			return ~p ? p : find_suf(rc, M + 1, R, v, cv);
		}
	}

	int pa[N], fc[N], nc[N], deg[N];

	inline void link(int x, int px) {pa[x] = px, nc[x] = fc[px], fc[px] = x, ++deg[px];}

	void build() {
		int i, l, top1 = 0, top2 = 0, top = 0, &v = root, u; cnt = n;
		for (i = 1; i <= n; ++i) st[0][i] = pr(p[i], p[i]), left[i] = right[i] = i, I[i] = leaf;
		build_sparse_table(), ST::build(1, 1, n);
		for (i = 1; i <= n; ++i) {
			for (; top1 && p[i] > p[ stack1[top1] ]; --top1)
				ST::add(1, 1, n, stack1[top1 - 1] + 1, stack1[top1], p[i] - p[ stack1[top1] ]);
			for (; top2 && p[i] < p[ stack2[top2] ]; --top2)
				ST::add(1, 1, n, stack2[top2 - 1] + 1, stack2[top2], p[ stack2[top2] ] - p[i]);
			stack1[++top1] = stack2[++top2] = i;
			l = ST::find_suf(1, 1, n, i);
			for (v = i; top && left[ u = stack[top] ] >= l; --top)
				if (I[u] == conjunct && is_consecutive(mid[u], i + 1))
					right[u] = i, link(v, u), v = u;
				else if (is_consecutive(left[u], i + 1)) {
					I[++cnt] = conjunct, link(u, cnt), link(v, cnt);
					left[cnt] = left[u], right[cnt] = i, mid[cnt] = left[v], v = cnt;
				} else {
					I[++cnt] = disjunct, link(v, cnt);
					for (; top && !is_consecutive(left[ u = stack[top] ], i + 1); --top)
						link(u, cnt); link(u, cnt);
					left[cnt] = left[u], right[cnt] = i, v = cnt;
				}
			stack[++top] = v;
		}
	}
}

Chtholly 树 (ODT) / set 维护连续段 [#ds12]:

namespace CTree {
	map C;

	map::iterator split(int pos) {
		map::iterator it = C.lower_bound(pos), jt = it;
		return it->first == pos ? it : C.emplace_hint(it, pos, (--jt)->second);
	}

	void modify(int l, int r, int v) {
		map::iterator it = split(l), jt = split(r), i, j;
		for (j = it; (i = j++) != jt; ) // do something on [i, j]
		C.erase(it, jt), C.emplace(l, v); // do something
	}
}

可删除的堆 [#ds13]:

struct heap {
	std::priority_queue <int, std::vector <int>, std::greater <int>> A, B;

	inline void emplace(int x) {A.emplace(x);}
	inline void erase(int x) {B.emplace(x);}
	inline void normalize() {for (; !B.empty() && A.top() == B.top(); A.pop(), B.pop());}
	inline int top() {return normalize(), A.empty() ? INF : A.top();}
	inline bool pop() {return normalize(), !A.empty() && (A.pop(), true);}
	inline void clear() {for (; !A.empty(); A.pop()); for (; !B.empty(); B.pop());}
};

IO 优化 [#ed01]:

#define ID isdigit(c = *next++)
#define IS isspace(c = *next++)

struct Istream {
	char *next, buf[20030731];
	Istream & init(FILE *f = stdin) {fread(buf, 1, sizeof buf, f); next = buf; return *this;}
	Istream & operator >> (int &x) {
		int c; x = 0;
		for (; !ID; ) if (!~c) return *this;
		for (x = c & 15; ID; x = x * 10 + (c & 15));
		return *this;
	}
	Istream & operator >> (char *x) {
		int c;
		for (; IS; ) if (!~c) return *this;
		for (*x++ = c; !IS; *x++ = c) if (!~c) break;
		return *x = 0, *this;
	}
	char get() {return *next++;}
} cin;

struct Ostream {
	char *next, buf[20030731], _buf[34];
	Ostream () {next = buf;}
	void flush(FILE *f = stdout) {fwrite(buf, 1, next - buf, f); next = buf;}
	Ostream & operator << (int x) {
		if (!x) return put(48), *this;
		int i;
		for (i = 0; x; x /= 10) _buf[++i] = x % 10 | 48;
		for (; i; --i) put(_buf[i]);
		return *this;
	}
	Ostream & operator << (char c) {return put(c), *this;}
	Ostream & operator << (const char *s) {for (char *p = (char*)s; *p; ++p) put(*p); return *this;}
	void put(char c) {*next++ = c;}
} cout;

动态规划的转移 [#ed02]:

inline void up(int &x, const int y) {x < y ? x = y : 0;}
inline void down(int &x, const int y) {x > y ? x = y : 0;}
inline int min(const int x, const int y) {return x < y ? x : y;}
inline int max(const int x, const int y) {return x < y ? y : x;}
inline int & reduce(int &x) {return x += x >> 31 & mod;}
inline void add(int &x, const int y) {x += y - mod, x += x >> 31 & mod;}
inline void sub(int &x, const int y) {x -= y, x += x >> 31 & mod;}
inline int & half(int &x) {return x = (x >> 1) + (-(x & 1) & iv2);}
inline int & neg(int &x) {return x = (!x - 1) & (mod - x);}

// another ver.
inline bool up(int &x, const int y) {return x < y ? x = y, 1 : 0;}
inline bool down(int &x, const int y) {return x > y ? x = y, 1 : 0;}
inline int & add(int &x, const int y) {return x += y - mod, x += x >> 31 & mod;}
inline int & sub(int &x, const int y) {return x -= y, x += x >> 31 & mod;}

// templated ver.
#define templated template <typename T>
inline bool up(T &x, const T y) {return x < y ? x = y, 1 : 0;}
inline bool down(T &x, const T y) {return x > y ? x = y, 1 : 0;}
inline T min(const T x, const T y) {return x < y ? x : y;}
inline T max(const T x, const T y) {return x < y ? y : x;}

乘模函数 (64 bit 大整数相乘取模) [#ed03]:

inline ll MulMod(ll a, ll b, ll m) {
	ll t = (a * b - (ll)((ld)a * b / m) * m) % m;
	return t + (t >> 63 & m);
}

ST 表 [#ed04]:

namespace RMQ_simple {
	void build_sparse_table() {
		int *f, *g = *st, i, j, k = n;
		for (j = 0; 1 << (j + 1) <= n; ++j) {
			f = g, g = st[j + 1], k -= 1 << j;
			for (i = 0; i < k; ++i)
				g[i] = min(f[i], f[i + (1 << j)]);
		}
	}

	inline int range(int L, int R) {
		int c = lg2(R - L);
		return min(st[c][L], st[c][R - (1 << c)]);
	}
}

namespace RMQ_fake {
	const int LN = 18, TH = 18;

	int n, *a, pre[N], suf[N], bel[N];
	int L, st[LN][N / TH], *lay = *st;

	void build(int n_, int *a_) {
		int i, j, k, I, *f, *g = lay; n = n_, a = a_;
		for (I = i = 0; I < n; ++i, I += TH) {
			pre[I] = a[I], bel[I] = i;
			for (j = 1; j < TH && I + j < n; ++j) pre[I + j] = min(pre[I + j - 1], a[I + j]), bel[I + j] = i;
			for (--j, suf[I + j] = a[I + j]; --j >= 0; suf[I + j] = min(suf[I + j + 1], a[I + j]));
			lay[i] = suf[I];
		}
		for (k = L = i, j = 0; 1 << (j + 1) <= L; ++j)
			for (f = g, g = st[j + 1], k -= 1 << j, i = 0; i < k; ++i)
				g[i] = min(f[i], f[i + (1 << j)]);
	}

	inline int range(int L, int R) {
		if (R <= L + TH) return *std::min_element(a + L, a + R);
		int x = bel[L] + 1, y = bel[--R], c = lg2(y - x);
		return min(min(suf[L], pre[R]), x < y ? min(st[c][x], st[c][y - (1 << c)]) : INT_MAX);
	}
}

离散化 [#ed05]:

namespace DC {
	int F[N]; pr D[N];

	int Discretize(int n) {
		int i, cnt = 0; std::sort(D, D + n);
		for (i = 0; i < n; ++i)
			F[D[i].second] = (i && D[i].first == D[i - 1].first ? cnt - 1 : (D[cnt] = D[i], cnt++));
		return cnt;
	}
}

Hash Map [#ed06]:

class hash_map{
public:
	static const int HASH_MAX = 0xffffff, N = 8000000;
	int cnt, first[HASH_MAX + 2], next[N]; data z[N];
	inline int getHash(int key) {return (key ^ key << 3 ^ key >> 2) & HASH_MAX;}

	void clear() {for(; cnt > 0; --cnt) first[z[cnt].hash] = 0;}

	data * find(int key, bool inserted){
		int x = getHash(key), i;
		for(i = first[x]; i; i = next[i]) if(z[i].key == key) return z + i;
		if(!inserted) return NULL;
		z[++cnt] = data(key, 0, x); next[cnt] = first[x]; first[x] = cnt;
		return z + cnt;
	}
};

快速 Fourier 变换 (Fast Fourier Transform) [#ed07]:

// 'Fast Number Theory Transform' is in memos/12.html.
typedef std::complex <double> C;

namespace rpoly_base {
	int l, n; double iv; C w2[N];

	void init(int n = N) {
		int i, t = min(n > 1 ? lg2(n - 1) : 0, 21); double angle = pi;
		for (*w2 = C(1), i = 0; i <= t; ++i) w2[1 << i] = std::polar(1., angle *= .5);
		for (i = 3; i < n; ++i) if (i & (i - 1)) w2[i] = w2[i & (i - 1)] * w2[i & -i];
	}

	inline void FFT_init(int len) {n = 1 << (l = len), iv = 1. / n;}

	void DIF(C *a) {
		int i, len = n >> 1; C *j, *k, *o, R;
		for (i = 0; i < l; ++i, len >>= 1)
			for (j = a, o = w2; j != a + n; j += len << 1, ++o)
				for (k = j; k != j + len; ++k)
					R = *o * k[len], k[len] = *k - R, *k += R;
	}

	void DIT(C *a) {
		int i, len = 1; C *j, *k, *o, R;
		for (i = 0; i < l; ++i, len <<= 1)
			for (j = a, o = w2; j != a + n; j += len << 1, ++o)
				for (k = j; k != j + len; ++k)
					R = *k + k[len], k[len] = (*k - k[len]) * *o, *k = R;
	}
}

namespace rpoly {
	using namespace rpoly_base;

	C B1[N], B2[N], B3[N], B4[N];

	void mulf(int A, int B, double *a, double *b, double *c) {
		if (!(A || B)) {*c = *a * *b; return;}
		int i; FFT_init(lg2(A + B) + 1);
		for (i = 0; i <= A; ++i) B1[i] = C(a[i]); memset(B1 + i, 0, (n - i) << 4);
		for (i = 0; i <= B; ++i) B2[i] = C(b[i]); memset(B2 + i, 0, (n - i) << 4);
		DIF(B1), DIF(B2);
		for (i = 0; i < n; ++i) B1[i] *= B2[i];
		DIT(B1), std::reverse(B1 + 1, B1 + n);
		for (i = 0; i <= A + B; ++i) c[i] = B1[i].real() * iv;
	}

	void muli(int A, int B, int *a, int *b, int *c) {
		if (!(A || B)) {*c = (ll)*a * *b % mod; return;}
		int i, j, k; FFT_init(lg2(A + B) + 1);
		for (i = 0; i <= A; ++i) B1[i] = C(a[i] & 32767, a[i] >> 15); memset(B1 + i, 0, (n - i) << 4);
		for (i = 0; i <= B; ++i) B2[i] = C(b[i] & 32767, b[i] >> 15); memset(B2 + i, 0, (n - i) << 4);
		DIF(B1), DIF(B2);
		*B3 = B1->real() * *B2, *B4 = B1->imag() * *B2;
		for (k = 0; k < l; ++k)
			for (i = 1 << k, j = (2 << k) - 1; i < 2 << k; ++i, --j)
				B3[j] = (B1[i] + std::conj(B1[j])) * B2[i] * C(.5, 0.),
				B4[j] = (B1[i] - std::conj(B1[j])) * B2[i] * C(0., -.5);
		DIT(B3), DIT(B4);
		for (i = 0; i <= A + B; ++i)
			c[i] = (ll(B3[i].real() * iv + .5) + (ll((B3[i].imag() + B4[i].real()) * iv + .5) % mod << 15) + (ll(B4[i].imag() * iv + .5) % mod << 30) + mod) % mod;
	}
}

Gauss 消元法 [#ed08]:

// Gauss elimination with type 'double'
struct LnEqn{
	int sz;
	double **m, *b;
	LnEqn (): sz(0) {m = NULL; b = NULL;}
	void resize(int size){
		sz = size; m = new double *[sz];
		for(int i = 0; i < sz; i++){
			m[i] = new double[sz];
			memset(m[i], 0, sz << 3);
		}
		b = new double[sz];
		memset(b, 0, sz << 3);
	}
	~LnEqn (){
		if(m) {for(int i = 0; i < sz; i++) delete [] (m[i]); delete [] (m);}
		if(b) delete [] (b);
	}
	bool solve(){
		int i, j, k, maxi; double coe;
		for(k = 0; k < sz; k++){
			maxi = k;
			for(i = k + 1; i < sz; i++)
				if(fabs(m[i][k]) > fabs(m[maxi][k]))
					maxi = i;
			if(fabs(m[maxi][k]) < 1e-8) return false;
			if(maxi != k){
				swap(m[maxi], m[k]);
				swap(b[maxi], b[k]);
			}
			coe = 1.0 / m[k][k];
			for(j = 0; j < sz; j++)
				m[k][j] *= coe;
			m[k][k] = 1.0;
			b[k] *= coe;
			for(i = 0; i < sz; i++){
				if(i == k) continue;
				coe = m[i][k];
				for(j = 0; j < sz; j++)
					m[i][j] -= coe * m[k][j];
				m[i][k] = 0.0;
				b[i] -= coe * b[k];
			}
		}
		return true;
	}
};

线性规划 (xₚ ≥ 0, bₚ ≥ 0) [#ed09]:

const double eps = 1e-8;

int id[N + E];

double m[E][N], b[E], *c = m[0], ans[N + E];

void pivot(int toFree, int toBasic); // basic(1,m) -> free, free(1,n) -> basic

void pivot(int r, int c){
	int i, j; double coe = 1.0 / m[r][c];
	swap(id[n + r], id[c]);
	m[r][c] = 1.0;
	for(j = 1; j <= n; ++j)
		m[r][j] *= coe;
	b[r] *= coe;
	for(i = 0; i <= e; ++i){
		if(i == r) continue;
		coe = m[i][c]; m[i][c] = 0.0;
		for(j = 1; j <= n; ++j)
			m[i][j] -= coe * m[r][j];
		b[i] -= coe * b[r];
	}
}

bool simplex(){
	int i, j, basic, free; double G;
	for(; ; ){
		basic = free = 0; G = INFINITY;
		for(i = 1; i <= n; ++i) // free (nonbasic) variable
			if(c[i] > c[free]) free = i;
		if(!free) return true;
		for(j = 1; j <= e; ++j) // basic variable
			if(m[j][free] > eps && b[j] < G * m[j][free]){
				G = b[j] / m[j][free]; basic = j;
			}
		if(!basic) return puts("Unbounded"), false;
		pivot(basic, free);
	}
}

// initialize :
for(j = 1; j <= n + e; ++j) id[j] = j;
c[0] = eps;

// output:
if(simplex()){
	printf("%.8lg\n", -*b);
	for(i = 1; i <= e; ++i) ans[id[n + i]] = b[i];
	for(j = 1; j <= n; ++j) printf("%.8lg%c", ans[j], j == n ? 10 : 32);
}

Gauss 消元求行列式 (模意义) [#ed10]:

int gauss(int n) {
	int i, j, k, det = 1; ll coe;
	static int *m[N];
	for (i = 0; i < n; ++i) m[i] = mat[i];
	for (i = 0; i < n; ++i) {
		for (j = i; j < n && !m[j][i]; ++j);
		if (j == n) return 0;
		if (i != j) det = mod - det, std::swap(m[i], m[j]);
		det = (ll)det * m[i][i] % mod;
		coe = PowerMod(m[i][i], mod - 2);
		for (j = 0; j < n; ++j) m[i][j] = m[i][j] * coe % mod;
		for (k = i + 1; k < n; ++k)
			for (coe = mod - m[k][i], j = i; j < n; ++j) m[k][j] = (m[k][j] + coe * m[i][j]) % mod;
	}
	return det;
}

Nim 积 (32/64 bit) [#ed11]:

namespace nimbers {
	constexpr u32 n2f[16] = {0x0001u, 0x8ff5u, 0x6cbfu, 0xa5beu, 0x761au, 0x8238u, 0x4f08u, 0x95acu, 0xf340u, 0x1336u, 0x7d5eu, 0x86e7u, 0x3a47u, 0xe796u, 0xb7c3u, 0x0008u},
				  f2n[16] = {0x0001u, 0x2827u, 0x392bu, 0x8000u, 0x20fdu, 0x4d1du, 0xde4au, 0x0a17u, 0x3464u, 0xe3a9u, 0x6d8du, 0x34bcu, 0xa921u, 0xa173u, 0x0ebcu, 0x0e69u};
	inline u32 nimber2field(u32 x) {u32 y = 0; for (; x; x &= x - 1) y ^= n2f[ctz(x)]; return y;}
	inline u32 field2nimber(u32 x) {u32 y = 0; for (; x; x &= x - 1) y ^= f2n[ctz(x)]; return y;}
	inline u32 __builtin_double(u32 x) {return x << 1 ^ (x < 0x8000u ? 0 : 0x1681fu);}

	u16 ln[65536], exp[131075], *Hexp = exp + 3, *H2exp = exp + 6;

	inline void init() {
		int i;
		for (*exp = i = 1; i < 65535; ++i) exp[i] = __builtin_double(exp[i - 1]);
		for (i = 1; i < 65535; ++i) exp[i] = field2nimber(exp[i]), ln[exp[i]] = i;
		memcpy(exp + 65535, exp, 131070);
		memcpy(exp + 131070, exp, 10);
	}

	inline u16 product(u16 A, u16 B) {return A && B ? exp[ln[A] + ln[B]] : 0;}
	inline u16 H(u16 A) {return A ? Hexp[ln[A]] : 0;}
	inline u16 H2(u16 A) {return A ? H2exp[ln[A]] : 0;}
	inline u16 Hproduct(u16 A, u16 B) {return A && B ? Hexp[ln[A] + ln[B]] : 0;}

	inline u32 product(u32 A, u32 B) {
		u16 a = A & 65535, b = B & 65535, c = A >> 16, d = B >> 16, e = product(a, b);
		return u32(product(u16(a ^ c), u16(b ^ d)) ^ e) << 16 | (Hproduct(c, d) ^ e);
	}

	inline u32 H(u32 A) {
		u16 a = A & 65535, b = A >> 16;
		return H(u16(a ^ b)) << 16 | H2(b);
	}

	inline u64 product(u64 A, u64 B) {
		u32 a = A & UINT_MAX, b = B & UINT_MAX, c = A >> 32, d = B >> 32, e = product(a, b);
		return u64(product(a ^ c, b ^ d) ^ e) << 32 | (H(product(c, d)) ^ e);
	}
}

二维向量/点、计算几何基础 [#cg01]:

const double eps = 1e-8;

#define lt(x, y) ((x) < (y) - eps)
#define gt(x, y) ((x) > (y) + eps)
#define le(x, y) ((x) <= (y) + eps)
#define ge(x, y) ((x) >= (y) - eps)
#define eq(x, y) (le(x, y) && ge(x, y))
#define dot(x, y, z) (((y) - (x)) * ((z) - (x)))
#define cross(x, y, z) (((y) - (x)) ^ ((z) - (x)))

struct vec2 {
	double x, y;
	vec2 (double x0 = 0.0, double y0 = 0.0) : x(x0), y(y0) {}
	vec2 * read() {scanf("%lf%lf", &x, &y); return this;}
	inline vec2 operator - () const {return vec2(-x, -y);}
	inline vec2 operator + (const vec2 &B) const {return vec2(x + B.x, y + B.y);}
	inline vec2 operator - (const vec2 &B) const {return vec2(x - B.x, y - B.y);}
	inline vec2 operator * (double k) const {return vec2(x * k, y * k);}
	inline vec2 operator / (double k) const {return *this * (1.0 / k);}
	inline double operator * (const vec2 &B) const {return x * B.x + y * B.y;}
	inline double operator ^ (const vec2 &B) const {return x * B.y - y * B.x;}
	inline double norm2() const {return x * x + y * y;}
	inline double norm() const {return sqrt(x * x + y * y);}
	inline bool operator < (const vec2 &B) const {return lt(x, B.x) || le(x, B.x) && lt(y, B.y);}
	inline bool operator == (const vec2 &B) const {return eq(x, B.x) && eq(y, B.y);}
	inline bool operator << (const vec2 &B) const {return lt(y, 0) ^ lt(B.y, 0) ? lt(B.y, 0) : gt(*this ^ B, 0) || ge(*this ^ B, 0) && ge(x, 0) && lt(B.x, 0);}
	inline vec2 trans(double a11, double a12, double a21, double a22) const {return vec2(x * a11 + y * a12, x * a21 + y * a22);}
};

/*
operator * : Dot product
operator ^ : Cross product
norm2() : |v|^2 = v.v
norm() : |v| = sqrt(v.v)
operator < : Two-key compare
operator << : Polar angle compare
trans : Transition with a 2x2 matrix
*/

直线及其函数 [#cg02]:

struct line {
	double A, B, C; // Ax + By + C = 0, > 0 if it represents halfplane.
	line (double A0 = 0.0, double B0 = 0.0, double C0 = 0.0) : A(A0), B(B0), C(C0) {}
	line (const vec2 &u, const vec2 &v) : A(u.y - v.y), B(v.x - u.x), C(u ^ v) {} // left > 0
	inline vec2 normVec() const {return vec2(A, B);}
	inline double norm2() const {return A * A + B * B;}
	inline double operator () (const vec2 &P) const {return A * P.x + B * P.y + C;}
};

inline vec2 intersection(const line u, const line v) {return vec2(u.B * v.C - u.C * v.B, u.C * v.A - u.A * v.C) / (u.A * v.B - u.B * v.A);}

inline bool parallel(const line u, const line v) {double p = u.normVec() ^ v.normVec(); return eq(p, 0);}

inline bool perpendicular(const line u, const line v) {double p = u.normVec() * v.normVec(); return eq(p, 0);}

inline bool sameDir(const line u, const line v) {return parallel(u, v) && gt(u.normVec() * v.normVec(), 0);}

inline line bisector(const vec2 u, const vec2 v) {return line(v.x - u.x, v.y - u.y, 0.5 * (u.norm2() - v.norm2()));}

inline double dis2(const vec2 P, const line l) {return l(P) * l(P) / l.norm2();}

inline vec2 projection(const vec2 P, const line l) {return P - l.normVec() * (l(P) / l.norm2());}

inline vec2 symmetry(const vec2 P, const line l) {return P - l.normVec() * (2 * l(P) / l.norm2());}

多边形操作 [#cg03]:

// Relation of 3 points. (2 inside, 1 outside, 0 not collinear)
inline int collinear(const vec2 u, const vec2 v, const vec2 P) {double p = cross(P, u, v); return eq(p, 0) ? 1 + le(dot(P, u, v), 0) : 0;}

// Perimeter of a polygon
double perimeter(int n, vec2 *poly) {
	double ret = (poly[n - 1] - *poly).norm();
	for (int i = 1; i < n; ++i) ret += (poly[i - 1] - poly[i]).norm();
	return ret;
}

// Directed area of a polygon (positive if CCW)
double area(int n, vec2 *poly) {
	double ret = poly[n - 1] ^ *poly;
	for (int i = 1; i < n; ++i) ret += poly[i - 1] ^ poly[i];
	return ret * 0.5;
}

// Point in polygon (2 on boundary, 1 inside, 0 outside)
int contain(int n, vec2 *poly, const vec2 P) {
	int in = 0; vec2 *r = poly + (n - 1), *u, *v;
	for (int i = 0; i < n; r = poly, ++poly, ++i) {
		if (collinear(*r, *poly, P) == 2) return 2;
		gt(r->y, poly->y) ? (u = poly, v = r) : (u = r, v = poly);
		if (ge(P.y, v->y) || lt(P.y, u->y)) continue;
		in ^= gt(cross(P, *u, *v), 0);
	}
	return in;
}

平面凸包 (Graham Scan) [#cg04]:

int graham(int n, vec2 *p, vec2 *dest) {
	int i; vec2 *ret = dest;
	std::iter_swap(p, std::min_element(p, p + n));
	std::sort(p + 1, p + n, [p] (const vec2 A, const vec2 B) {double r = cross(*p, A, B); return gt(r, 0) || (ge(r, 0) && lt((A - *p).norm2(), (B - *p).norm2()));});
	for (i = 0; i < 2 && i < n; ++i) *ret++ = p[i];
	for (; i < n; *ret++ = p[i++])
		for (; ret != dest + 1 && ge(cross(ret[-2], p[i], ret[-1]), 0); --ret);
	return *ret = *p, ret - dest;
}

旋转卡壳求凸集直径 [#cg05]:

double convDiameter(int n, vec2 *poly) {
	int l = std::min_element(poly, poly + n) - poly, r = std::max_element(poly, poly + n) - poly, i = l, j = r;
	double diam = (poly[l] - poly[r]).norm2();
	do {
		(ge(poly[(i + 1) % n] - poly[i] ^ poly[(j + 1) % n] - poly[j], 0) ? ++j : ++i) %= n;
		up(diam, (poly[i] - poly[j]).norm2());
	} while (i != l || j != r);
	return diam;
}

三角形外心 & 最小圆覆盖 [#cg06]:

inline vec2 circumCenter(const vec2 A, const vec2 B, const vec2 C) {
	vec2 a = B - A, b = C - A, AO;
	double det = 0.5 / (a ^ b), na = a.norm2(), nb = b.norm2();
	AO = vec2((na * b.y - nb * a.y) * det, (nb * a.x - na * b.x) * det);
	return A + AO;
}

double minCircleCover(int n, vec2 *p, vec2 *ret = NULL) {
	int i, j, k; double r2 = 0.0;
	std::random_shuffle(p + 1, p + (n + 1));
	vec2 C = p[1];
	for (i = 2; i <= n; ++i)
		if (gt((p[i] - C).norm2(), r2))
			for (C = p[i], r2 = 0, j = 1; j < i; ++j)
				if (gt((p[j] - C).norm2(), r2))
					for (C = (p[i] + p[j]) * 0.5, r2 = (p[j] - C).norm2(), k = 1; k < j; ++k)
						if (gt((p[k] - C).norm2(), r2))
							C = circumCenter(p[i], p[j], p[k]), r2 = (p[k] - C).norm2();
	return ret ? *ret = C : 0, r2;
}

半平面交 (平行处理版) [#cg07]:

inline bool HPIcmp(const line u, const line v) {return sameDir(u, v) ? gt((fabs(u.A) + fabs(u.B)) * v.C, (fabs(v.A) + fabs(v.B)) * u.C) : u.normVec() << v.normVec();}

inline bool geStraight(const vec2 A, const vec2 B) {return lt(A ^ B, 0) || le(A ^ B, 0) && lt(A * B, 0);}

inline bool para_nega_test(const line u, const line v) {
	return parallel(u, v) && lt(u.normVec() * v.normVec(), 0) && (fabs(u.A) + fabs(u.B)) * v.C + (fabs(v.A) + fabs(v.B)) * u.C < -7e-14;
}

int HPI(int n, line *l, vec2 *poly, vec2 *&ret) { // -1 : Unbounded, -2 : Infeasible
	int h = 0, t = -1, i, j, que[n + 5];
	std::sort(l, l + n, HPIcmp);
	n = std::unique(l, l + n, sameDir) - l;
	for (j = i = 0; i < n && j < n; ++i) {
		for (up(j, i + 1); j < n && !geStraight(l[i].normVec(), l[j].normVec()); ++j);
		if (para_nega_test(l[i], l[j])) return -2;
	}
	if (n <= 2 || geStraight(l[n - 1].normVec(), l->normVec())) return -1;
	for (i = 0; i < n; ++i) {
		if (geStraight(l[que[t]].normVec(), l[i].normVec())) return -1;
		for (; h < t && le(l[i](poly[t - 1]), 0); --t);
		for (; h < t && le(l[i](poly[h]), 0); ++h);
		que[++t] = i; h < t ? poly[t - 1] = intersection(l[ que[t - 1] ], l[ que[t] ]) : 0;
	}
	for (; h < t && le(l[ que[h] ](poly[t - 1]), 0); --t);
	return h == t ? -2 : (poly[t] = intersection(l[ que[t] ], l[ que[h] ]), ret = poly + h, t - h + 1);
}

平面上的圆几何 [#cg08]:

const double pi = M_PI, pi2 = pi * 2., pi_2 = M_PI_2;

inline double angle(const vec2 u, const vec2 v) {return atan2(u ^ v, u * v);}

// intersection of circle and line
int intersection(double r2, const vec2 O, const line l, vec2 *ret) {
	double d2 = dis2(O, l); vec2 j = l.normVec();
	if (gt(d2, r2)) return ret[0] = ret[1] = vec2(INFINITY, INFINITY), 0;
	if (ge(d2, r2)) return ret[0] = ret[1] = projection(O, l), 1;
	if (le(d2, 0)) {
		j = j * sqrt(r2 / j.norm2());
		ret[0] = O + j.trans(0, -1, 1, 0);
		ret[1] = O + j.trans(0, 1, -1, 0);
	} else {
		double T = copysign(sqrt((r2 - d2) / d2), l(O)); j = j * (-l(O) / j.norm2());
		ret[0] = O + j.trans(1, T, -T, 1);
		ret[1] = O + j.trans(1, -T, T, 1);
	}
	return 2;
}

// area of intersection(x^2 + y^2 = r^2, triangle OBC)
double interArea(double r2, const vec2 B, const vec2 C) {
	if (eq(B ^ C, 0)) return 0;
	vec2 is[2];
	if (!intersection(r2, vec2(), line(B, C), is)) return 0.5 * r2 * angle(B, C);
	bool b = gt(B.norm2(), r2), c = gt(C.norm2(), r2);
	if (b && c) return 0.5 * (lt(dot(*is, B, C), 0) ? r2 * (angle(B, *is) + angle(is[1], C)) + (is[0] ^ is[1]) : r2 * angle(B, C));
	else if (b) return 0.5 * (r2 * angle(B, *is) + (*is ^ C));
	else if (c) return 0.5 * ((B ^ is[1]) + r2 * angle(is[1], C));
	else return 0.5 * (B ^ C);
}

// tangents to circle((0, 0), r) through P
int tangent(double r, const vec2 P, line *ret) {
	double Q = P.norm2() - r * r;
	if (lt(Q, 0)) return ret[0] = ret[1] = line(INFINITY, INFINITY, INFINITY), 0;
	if (le(Q, 0)) return ret[0] = ret[1] = line(P.x, P.y, -P.norm2()), 1;
	Q = sqrt(Q) / r;
	ret[0] = line(P.x + Q * P.y, P.y - Q * P.x, -P.norm2());
	ret[1] = line(P.x - Q * P.y, P.y + Q * P.x, -P.norm2());
	return 2;
}

// tangets to circle(O, r) through P
int tangent(double r, const vec2 O, const vec2 P, line*ret) {
	int R = tangent(r, P - O, ret);
	if (R)
		ret[0].C -= ret[0].A * O.x + ret[0].B * O.y,
		ret[1].C -= ret[1].A * O.x + ret[1].B * O.y;
	return R;
}

三维计算几何基础 [#cg09]:

#define triple(x, y, z) ((x) * ((y) ^ (z)))

struct vec3 {
	double x, y, z;
	vec3 (double x0 = 0, double y0 = 0, double z0 = 0) : x(x0), y(y0), z(z0) {}
	vec3 * read() {scanf("%lf%lf%lf", &x, &y, &z); return this;}
	inline vec3 operator - () const {return vec3(-x, -y, -z);}
	inline vec3 operator + (const vec3 &B) const {return vec3(x + B.x, y + B.y, z + B.z);}
	inline vec3 operator - (const vec3 &B) const {return vec3(x - B.x, y - B.y, z - B.z);}
	inline vec3 operator * (double k) const {return vec3(x * k, y * k);}
	inline vec3 operator / (double k) const {return *this * (1.0 / k);}
	inline double operator * (const vec3 &B) const {return x * B.x + y * B.y + z * B.z;}
	inline vec3 operator ^ (const vec3 &B) const {return vec3(y * B.z - z * B.y, z * B.x - x * B.z, x * B.y - y * B.x);}
	inline double norm2() const {return x * x + y * y + z * z;}
	inline double norm() const {return sqrt(x * x + y * y + z * z);}
	inline bool operator < (const vec3 &B) const {return lt(x, B.x) || le(x, B.x) && (lt(y, B.y) || le(y, B.y) && lt(z, B.z));}
	inline bool operator == (const vec3 &B) const {return eq(x, B.x) && eq(y, B.y) && eq(z, B.z);}
};

// Positive if Right-hand rule
inline double volume(const vec3 A, const vec3 B, const vec3 C, const vec3 D) {return triple(B - A, C - A, D - A);}

struct line3 {
	vec3 P, t;
	line3 (vec3 _P = vec3(), vec3 _t = vec3()) : P(_P), t(_t) {}
};

inline double dis2(const vec3 P, const line3 l) {return ((P - l.P) ^ l.t).norm2() / l.t.norm2();}

struct plane {
	double A, B, C, D; // Ax + By + Cz + D = 0
	plane (double A0 = 0.0, double B0 = 0.0, double C0 = 0.0, double D0 = 0.0) : A(A0), B(B0), C(C0), D(D0) {}
	plane (const vec3 &u, const vec3 &v, const vec3 &w) {vec3 t = (v - u) ^ (w - u); A = t.x, B = t.y, C = t.z, D = -triple(u, v, w);} // > 0 if it follows Right-hand rule
	inline vec3normVec() const {return vec3(A, B, C);}
	inline double norm2() const {return A * A + B * B + C * C;}
	inline double operator () (const vec3&P) const {return A * P.x + B * P.y + C * P.z + D;}
};

inline double dis2(const vec3 P, const plane F) {return F(P) * F(P) / F.norm2();}

三维凸包 (卷包裹法) [#cg10]:

namespace CH3D {
	typedef std::pair <int, int> pr;
	typedef std::set <pr> set;

	struct triangle {vec3 A, B, C;} tr[N];

	vec3 p[N], q[N], r[N];
	set E;
	int n, cnt;

	inline vec3 randvec3() {return vec3((double)rand() / RAND_MAX, (double)rand() / RAND_MAX, (double)rand() / RAND_MAX);}

	void wrap(int u, int v) {
		if (E.find({u, v}) == E.end()) {
			int i, w = -1;
			for (i = 0; i < n; ++i)
				if (i != u && i != v && (!~w || ge(volume(q[w], q[u], q[v], q[i]), 0))) w = i;
			if (~w) {
				tr[cnt++] = (triangle){p[u], p[v], p[w]};
				E.emplace(u, v); E.emplace(v, w); E.emplace(w, u);
				wrap(w, v); wrap(u, w);
			}
		}
	}

	void main(int _n, vec3 *_p) {
		int i;
		n = _n; cnt = 0; E.clear();
		memcpy(p, _p, n * sizeof(vec3));
		std::iter_swap(p, std::min_element(p, p + n));
		for (i = 0; i < n; ++i) q[i] = p[i] + randvec3() * 1e-6;
		for (i = 2; i < n; ++i)
			if (ge(cross(q[0], q[i], q[1]).z, 0)) std::swap(p[1], p[i]), std::swap(q[1], q[i]);
		wrap(0, 1);
	}
}

自适应 Simpson 积分 [#cg11]:

double Simpson(double L, double M, double R, double fL, double fM, double fR, double eps) {
	double LM = (L + M) * 0.5, fLM = f(LM), MR = (M + R) * 0.5, fMR = f(MR);
	double A = (fL + fM * 4.0 + fR) * (R - L) * sixth,
		   AL = (fL + fLM * 4.0 + fM) * (M - L) * sixth,
		   AR = (fM + fMR * 4.0 + fR) * (R - M) * sixth;
	if (fabs(AL + AR - A) < eps) return (2.0 * (AL + AR) + A) * third;
	return Simpson(L, LM, M, fL, fLM, fM, eps * 0.6) + Simpson(M, MR, R, fM, fMR, fR, eps * 0.6);
}

本文作者:Altwilio

本文链接:https://www.cnblogs.com/William-Sg/p/16109735.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Altwilio  阅读(62)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起