板子

upd at 2025.02.16

其实早就断更了。如果想了解更多详情,请前往 Zctf1088 的博客【学习笔记/算法总结】

upd at 2025.02.09

鉴于前段时间校 OJ 上的博客爆炸。为避免重大损失,搬迁至此。

板子

前言

是在我学斜率优化dp的时候,觉得需要一些模板。纯粹就是按写入的顺序排的(由新到旧),一些简单的就没写。也没啥可说的,拿来给我自己用的,如果能帮助到别人就更好。不断在更新,一有比较复杂且框架清晰的算法,就会写上去。另外,做题过程中也会对此进行补充。如发现有问题或错误,请及时告知,谢谢。


数学
--高精度
const int maxn = 1005;
struct Int {
	int a[2 * maxn];
	Int() {
		memset(a, 0, sizeof(a));
	}
	Int(int x) {
		*this = x;
	}
	Int operator = (int & x) {
		for (int i = 0; x; i++, x /= 10) {
			a[i] = x % 10;
		}
		return *this;
	}
	bool operator == (const Int & b) const {
		for (int i = maxn - 1; i >= 0; i--) {
			if (a[i] ^ b.a[i]) return false;
		} 
		return true;
	}
	bool operator > (const Int & b) const {
		for (int i = maxn - 1; i >= 0; i--) {
			if (a[i] ^ b.a[i]) return a[i] > b.a[i];
		} 
		return false;
	}
	bool operator < (const Int & b)  const {
		for (int i = maxn - 1; i >= 0; i--) {
			if (a[i] ^ b.a[i]) return a[i] < b.a[i];
		} 
		return false;
	}
	Int operator + (const Int & b) const {
		Int c;
		for (int i = 0; i < 2 * maxn - 1; i++) {
			c.a[i] += a[i] + b.a[i];
			while (c.a[i] > 9) {
				c.a[i + 1] += 1;
				c.a[i] -= 10;
			}
		}
		return c;
	}
	Int operator - (const Int & b) const {
		Int c;
		for (int i = 0; i < 2 * maxn - 1; i++) {
			c.a[i] += a[i] - b.a[i];
			if (c.a[i] < 0) {
				c.a[i + 1] -= 1;
				c.a[i] += 10;
			}
		}
		return c;
	}
	Int operator * (const Int & b) const {
		Int c;
		for (int i = 0; i < maxn; i++) {
			for (int j = 0; j < maxn; j++) {
				c.a[i + j] += a[i] * b.a[j];
			}
		}
		for (int i = 0; i < 2 * maxn - 1; i++) {
			while (c.a[i] > 9) {
				c.a[i + 1] += 1;
				c.a[i] -= 10;
			}
		}
		return c;
	}
	bool operator != (const Int & b) { return !(*this == b); }
	bool operator <= (const Int & b) { return !(*this > b); }
	bool operator >= (const Int & b) { return !(*this < b); }
	Int operator += (const Int & b) { return *this = *this + b; }
	Int operator -= (const Int & b) { return *this = *this - b; }
	Int operator *= (const Int & b) { return *this = *this * b; }
	void read() {
		string s;
		cin >> s;
		int ll = s.size();
		for (int i = 0, j = ll - 1; j >= 0; i++, j--) {
			a[i] = s[j] - '0';
		}
	}
	void print() {
		int flag = 0;
		for (int i = 2 * maxn - 1; i >= 0; i--) {
			if (a[i]) flag = 1;
			if (flag || !i) putchar(a[i] + '0');
		}
	}
};
--快速幂
int fpow(int a, int x, int MOD) {
	a %= MOD;
	int ans = 1;
	while (x > 0) {
		if (x & 1) {
			ans = ans * a % MOD; 
		}
		a = a * a % MOD;
		x >>= 1;
	}
	return ans;
}
--欧几里得辗转相除法 最大公约数
int gcdd(int n, int m) {
	if (m == 0) return n;
	return gcdd(m, n % m);
}
--扩展欧几里得

\(ax+by=\gcd(a,b)\) 的一组正整数解(\(x\)\(y\)为未知数)

构造通解

\(x=x_0+\frac{b}{\gcd(a,b)}*k\)

\(y=y_0-\frac{a}{\gcd(a,b)}*k\)

int exgcd(int a, int b, int &x, int &y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int ret = exgcd(b, a % b, x, y);
	int t = x;
	x = y;
	y = t - a / b * y;
	return ret;
}

求不定方程 \(ax+by=c\) 的一组整数解

  1. \(\gcd(a,b) \mid c\),则有整数解
    先用扩欧求 \(ax+by=\gcd(a,b)\) 的解
    再乘以 \(\frac{c}{\gcd(a,b)}\),即得原方程特解\((x_0,y_0)\)
  2. \(\gcd(a,b) \nmid c\),则无整数解。

构造通解同上。

--乘法逆元

费马小定理求逆元(快速幂)

int ny(int x) {
    return fpow(x, MOD - 2);
}

扩展欧几里得求逆元

int ny(int num, int MOD) {
	int x, y;
	int g = exgcd(num, MOD, x, y);
	if (g == 1) {
		return (x + MOD) % MOD;
	} else {
		return -1;
	}
}

线性求逆元

ny[1] = 1;
for (int i = 2; i <= n; i++) {
	ny[i] = (1ll * p - p / i) * ny[p % i] % p;
}
--欧拉函数

\[\varphi(n)=n \times \prod_{i=1}^k (1-\frac{1}{p_i}) \]

int phi(int x) {
	int ans = x, n = x;
	for (int i = 2; i * i <= n; i++) {
		if (n % i == 0) {
			ans = ans * (1.0 - 1.0 / i);
			while (n % i == 0) n /= i;
		}
	}
	if (n > 1) ans = ans * (1.0 - 1.0 / n);
	return ans;
}
void init() {
	f[1] = 1;
	for (int i = 2; i < N; i++) {
		if (f[i] == 0) {
			p[++tot] = i;
			phi[i] = i - 1;
		}
		for (int j = 1; j <= tot; j++) {
			if (i * p[j] >= N) break;
			f[i * p[j]] = 1;
			if (i % p[j] == 0) {
				phi[i * p[j]] = p[j] * phi[i];
			} else {
				phi[i * p[j]] = phi[p[j]] * phi[i];
			}
		}
	}
}
--欧拉定理

\(\gcd(a,m)=1\),则

\[a^{\varphi(m)} \equiv 1\pmod{m} \]

--扩展欧拉定理

\[a^{b} \equiv \left\{\begin{array}{ll} a^{b \bmod \varphi(p)}, & \operatorname{gcd}(a, p)=1 \\ a^{b}, & \operatorname{gcd}(a, p) \neq 1, b<\varphi(p) \pmod{p} \\ a^{b \bmod \varphi(p)+\varphi(p)}, & \operatorname{gcd}(a, p) \neq 1, b \geq \varphi(p) \\ \end{array}\right. \]

--组合数
int C(int n, int m) {
	if (n < m) {
		return 0;
	}
	return frac[n] * ny[m] % MOD * ny[n - m] % MOD;
}

frac[0] = ny[0] = 1; // 事实上阶乘应该是fact,但这个写习惯了
for (int i = 1; i <= n; i++) {
	frac[i] = frac[i - 1] * i % MOD;
	ny[i] = ny[i - 1] * fpow(i, MOD - 2) % MOD;
}
for (int i = 1; i <= n; i++) {
		C[i][0] = 1;
		for (int j = 1; j <= i; j++) {
			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
		}
	}
--lucas定理

可以用于求模数较小时且模数为质数的 \(C_n^m\)

int C(int n, int m) {
	if (n < m) return 0;
	return frac[n] * ny[m] % MOD * ny[n - m] % MOD;
}
int lucas(int n, int m) {
	if (m == 0) return 1;
	return lucas(n / MOD, m / MOD) * C(n % MOD, m % MOD) % MOD;
}
void init() {
	frac[0] = ny[0] = 1;
	for (int i = 1; i <= MOD; i++) {
		frac[i] = frac[i - 1] * i % MOD;
		ny[i] = ny[i - 1] * fpow(i, MOD - 2) % MOD;
	}
}
--矩阵乘法
struct mar {
	int m[M][M];
	mar() {
		for (int i = 0; i < M; i++) 
			for (int j = 0; j < M; j++) m[i][j] = 0;
	}
	il void init() {
		for (int i = 0; i < M; i++) m[i][i] = 1;
	}
	il int * operator [] (int x) {
		return m[x];
	}
	il mar operator * (mar x) const {
		mar	res;
		for (int i = 0; i < M; i++) 
			for (int j = 0; j < M; j++) 
				for (int k = 0; k < M; k++) 
					add(res[i][j], m[i][k] * x[k][j] % MOD);
		return res;
	}
};
--高斯消元
void gauss() {
    for (int i = 1; i <= n; i++) {
		int r = i;
		for (int k = i; k <= n; k++) {
			if (fabs(a[k][i]) > eps) {
				r = k;
				break;
			}
		}
		if (r != i) {
			swap(a[r], a[i]);
		}
		if (fabs(a[i][i]) < eps) {
			return;
		}
		for (int j = n + 1; j >= i; j--) {
			a[i][j] /= a[i][i];
		}
		for (int k = i + 1; k <= n; k++) {
			for (int j = n + 1; j >= i; j--) {
				a[k][j] -= a[k][i] * a[i][j];
			}
		}
	}
	for (int i = n - 1; i >= 1; i--) {
		for (int j = i + 1; j <= n; j++) {
			a[i][n + 1] -= a[i][j] * a[j][n + 1];
		}
	}
	return;
}
int gauss() {
	int c = 1;
	for (int i = 1; i <= n; i++) {
		int r = c;
		for (int k = c; k <= n; k++) {
			if (fabs(a[k][i]) > fabs(a[r][i])) {
				r = k;
			}
		}
		if (fabs(a[r][i]) < eps) {
			continue;
		}
		swap(a[r], a[c]);
		for (int k = n + 1; k >= i; k--) {
			a[c][k] /= a[c][i];
		}
		for (int k = c + 1; k <= n; k++) {
			if (fabs(a[k][i]) > eps) {
				for (int j = n + 1; j >= i; j--) {
					a[k][j] -= a[c][j] * a[k][i];
				}
			}
		}
		c++;
	}
	if (c <= n) {
		for (int i = c; i <= n; i++) {
			if (fabs(a[i][n + 1]) > eps) {
				return -1;
			}
		}
		return 0;
	}

	for (int i = n; i >= 1; i--) {
		for (int j = i + 1; j <= n; j++) {
			a[i][n + 1] -= a[j][n + 1] * a[i][j];
		}
	}
	return 1;
}
--二项式反演

\[F(n)=\sum_{i-k}^{n} C_{n}^{i} G(i) \Longleftrightarrow G(n)=\sum_{i-k}^{n}(-1)^{i-k} C_{i}^{k} F(i) \]

--中国剩余定理 CRT

求解线性同余方程组

\[\left\{\begin{array}{l} x \equiv r_{1} \pmod {m_{1}} \\ x \equiv r_{2} \pmod {m_{2}} \\ \vdots \\ x \equiv r_{n} \pmod {m_{n}} \end{array}\right. \]

(其中模数 \(m_1,m_2,\dots,m_n\) 为两两互质整数
\(x\) 的最小非负整数解。

int CRT(int m[], int r[]) {
	__int128 M = 1, ans = 0; // 数据太大了就用 __int128 
	for (int i = 1; i <= n; i++) M *= m[i];
	for (int i = 1; i <= n; i++) {
		__int128 c = M / m[i];
		ans = (ans + r[i] * c * ny(c, m[i]) % M) % M; // 用扩欧求逆元,因为模数不一定为质数 
	}
	return ans;
}
--扩展中国剩余定理

求解线性同余方程组

\[\left\{\begin{array}{l} x \equiv r_{1} \pmod {m_{1}} \\ x \equiv r_{2} \pmod {m_{2}} \\ \vdots \\ x \equiv r_{n} \pmod {m_{n}} \end{array}\right. \]

(其中模数 \(m_1,m_2,\dots,m_n\) 为不一定两两互质整数
\(x\) 的最小非负整数解。(两两互质,不代表两个数都是质数)

前两个方程: \(x \equiv r_{1} \pmod {m_{1}}, x \equiv r_{2} \pmod {m_{2}}\)

转化为不定方程: \(x=m_{1} p+r_{1}=m_{2} q+r_{2}\)

\(m_{1} p-m_{2} q=r_{2}-r_{1}\)

由裴蜀定理,

\(\gcd\left(m_{1}, m_{2}\right) \nmid\left(r_{2}-r_{1}\right)\) 时,无解

\(\gcd\left(m_{1}, m_{2}\right) \mid\left(r_{2}-r_{1}\right)\) 时,有解

由扩欧算法,

得特解 \(p=p * \frac{r_{2}-r_{1}}{g c d}, q=q * \frac{r_{2}-r_{1}}{g c d}\)

所以 \(x=m_{1} p+r_{1}=\frac{m_{1} m_{2}}{g c d} * k+m_{1} p+r_{1}\)

前两个方程等价合并为一个方程 \(x \equiv r \pmod m\)

其中 \(r=m_{1} p+r_{1}\)\(m=\operatorname{lcm}\left(m_{1}, m_{2}\right)\)

所以 \(n\) 个同余方程只要合并 \(n-1\) 次,即可求解

int EXCRT(int m[], int r[]) {
	__int128 m1, m2, r1, r2, p, q;
	m1 = m[1], r1 = r[1];
	for (int i = 2; i <= n; i++) {
		m2 = m[i], r2 = r[i];
		__int128 a = m1, b = m2, c = r2 - r1; // 扩展欧几里得 
		__int128 g = exgcd(a, b, p, q);
		if (c % g != 0) return -1; // 无解 
		p = p * c / g; // 特解
		p = (p % (b / g) + (b / g)) % (b / g);
		r1 = m1 * p + r1;
		m1 = m1 * m2 / g;
	}
	return (r1 % m1 + m1) % m1;
}
--卡特兰数

卡特兰数的常见公式:

\[H_{n}=\frac{\binom{2 n}{n}}{n+1}\left(n \geq 2, n \in \mathbf{N}_{+}\right) \]

\[H_{n}=\left\{\begin{array}{ll}\sum_{i=1}^{n} H_{i-1} H_{n-i} & n \geq 2, n \in \mathbf{N}_{+} \\1 & n=0,1\end{array}\right. \]

\[H_{n}=\frac{H_{n-1}(4 n-2)}{n+1} \]

\[H_{n}=\binom{2 n}{n}-\binom{2 n}{n-1} \]

--pollard
int pollard(int n, int c) {
	int x, y, d, i = 1, k = 2;
	x = wdz() * wdz() % (n - 1) + 1;
	y = x;
	while (1) {
		x = (mul(x, x, n) + c) % n;
		d = gcd((x - y + n) % n, n);
		if (1 < d && d < n) return d;
		if (x == y) return n;
		if (++i == k) {
			k <<= 1;
			y = x;
		}
	}
	return 23333333;
}
--Pollard Rho和Miller Rabin
int Test[15] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
int test_time = 12;
bool millerRabin(long long p) {
	if (p < 2) return 0;
	long long t = p - 1, k = 0;
	while (!(t & 1)) {
		t >>= 1;
		k++; 
	}
	for (long long i = 0; i < test_time; i++) {
		if (p == Test[i]) return 1;
		long long a = fpow(Test[i], t, p);
		for (long long j = 1; j <= k; j++) {
			if ((__int128)a * a % p == 1 && a != 1 && a != p - 1) {
				return 0;
			}
			a = (__int128)a * a % p;
		}
		if (a != 1) return 0;
	}
	return 1;
}
long long pollard(long long n, long long c) {
	long long x, y, d, i = 1, k = 2, v = 1;
	x = y = 0;
	while (1) {
		x = ((__int128)x * x % n + c) % n;
		v = (__int128)v * abs(x - y) % n;
		if (i % 127 == 0) {
			d = gcd(v, n);
			if (1 < d) return d;
		}
		if (x == y) return n;
		if (++i == k) {
			k <<= 1;
			y = x;
			d = gcd(v, n);
			if (1 < d) return d;
		}
	}
	return 23333333;
}
long long n, ans;
void resolve(long long x) {
	if (x == 1 || x <= ans) return;
	if (millerRabin(x)) {
		ans = max(ans, x);
		return;
	}
	long long p = x;
	while (p >= x) {
		p = pollard(x, wdz() % (x - 1) + 1);
	}
	while (x % p == 0) x /= p;
	resolve(x);
	resolve(p);
}
动态规划
--斜率优化dp

对于

\[\frac{dp_j-dp_k}{a_j-a_k}<b_i \]

int up(int j, int k) {
	return dp[j] - dp[k];
}
int down(int j, int k) {
	return a[j] - a[k];
}
int main() {
	memset(dp, INF, sizeof(dp));
	dp[0] = 0; 
	int head = 1, tail = 0;
	q[++tail] = 0;
	for (int i = 1; i <= n; i++) {
		while (head < tail && up(q[head + 1], q[head]) <= b[i] * down(q[head + 1], q[head])) {
			head++;
		}
		dp[i] = dp[q[head]]/*略*/;
		while (head < tail && up(q[tail], q[tail - 1]) * down(i, q[tail]) >= up(i, q[tail]) * down(q[tail], q[tail - 1])) {
			tail--;
		}
		q[++tail] = i;
	}
	printf("%lld\n", dp[n]);
	return 0;
}

对于

\[y=kx+b \]

将只与 \(j\) 有关的项放在左边,只与 \(i\) 有关的项放在右边,同时带有 \(i\)\(j\) 的项中以与 \(i\) 有关的参数作为斜率。且斜率不能为负。

int dp[N], q[N], head = 1, tail = 0;
int y(int j)
int k(int i)
int x(int j) 
int b(int i) 
double slope(int i, int j) {
	return 1.0 * (y(i) - y(j)) / (x(i) - x(j));
}
int main() {
	memset(dp, INF, sizeof(dp));
	dp[0] = 0; 
	q[++tail] = 0;
	for (int i = 1; i <= n; i++) {
		while (head < tail && slope(q[head], q[head + 1]) < k(i)) {
			head++;
		}
		// y = kx + b,转移 dp[i],略 
		while (head < tail && slope(q[tail - 1], q[tail]) >= slope(q[tail], i)) {
			tail--;
		}
		q[++tail] = i;
	}
	printf("%lld\n", dp[n]);
	return 0;
}
--状压dp

题目详情 - 「SCOI2005」互不侵犯 - gxyz (gxyzoj.com)

#include <bits/stdc++.h>

using namespace std;

const int N = 9 + 5;
const int M = (1 << 9) + 5;
const int K = N * N;
int n, k;
long long dp[N][K][M];
long long stt[M], cnt[M];

int lowbit(int x) {
	return x & -x;
}

int main() {
	scanf("%d%d", &n, &k);
	int ms = (1 << n) - 1;
	int tot = 0;
	for (int s = 0; s <= ms; s++) {
		for (int tmp = s; tmp > 0; tmp -= lowbit(tmp)) {
			cnt[s]++;
		}
		if (((s << 1) & s) == 0 && ((s >> 1) & s) == 0 && cnt[s] <= k) {
			stt[++tot] = s;
		}
	}
	dp[0][0][0] = 1;
	for (int i = 1; i <= n; i++) {
		for (int t1 = 1; t1 <= tot; t1++) {
			int s = stt[t1];
			for (int t2 = 1; t2 <= tot; t2++) {
				int ss = stt[t2];
				if ((ss & s) == 0 && ((ss << 1) & s) == 0 && ((ss >> 1) & s) == 0) {
					for (int j = 0; j <= k; j++) {
						if (cnt[s] <= j) {
							dp[i][j][s] += dp[i - 1][j - cnt[s]][ss];
						}
					}
				}
			}
		}
	}
	long long ans = 0;
	for (int i = 1; i <= tot; i++) {
		ans += dp[n][k][stt[i]];
	}
	printf("%lld\n", ans);

	return 0;
}
--单调队列优化dp

题目详情 - 「一本通 5.5 练习 1」烽火传递 - gxyz (gxyzoj.com)

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m;
int a[N];
deque<int> q;
int dp[N];
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	q.push_back(0);
	for (int i = 1; i <= n; i++) {
		if (q.front() < i - m) {
			q.pop_front();
		}
		dp[i] = dp[q.front()] + a[i];
		while (!q.empty() && dp[i] < dp[q.back()]) {
			q.pop_back();
		}
		q.push_back(i);
	}
	int ans = 0x3f3f3f3f;
	for (int i = n - m + 1; i <= n; i++) {
		ans = min(ans, dp[i]);
	}
	printf("%d\n", ans);
	return 0;
}

单调队列优化多重背包

#include <bits/stdc++.h>

using namespace std;

const int N = 5e2 + 10, M = 6e3 + 10;
int v[N], w[N], s[N];
int dp[N][M];
deque<int> q;

int main() {
	int m, n;
	scanf("%d%d", &n, &m);
	
	for (int i = 1; i <= n; i++) {
		scanf("%d%d%d", &v[i], &w[i], &s[i]); // 面值 体积 数量
	}
	
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j <= m; j++) {
			dp[i][j] = dp[i-1][j];
		}
		for (int r = 0; r < v[i]; r++) {
			while (!q.empty()) {
				q.pop_back();
			}
			for (int k = 0; k * v[i] + r <= m; k++) {
				if (!q.empty() && q.front() < k - s[i]) {
					q.pop_front();
				}
				while (!q.empty() && dp[i-1][k * v[i] + r] - k * w[i] >= dp[i-1][q.back() * v[i] + r] - q.back() * w[i]) {
					q.pop_back();
				}
				q.push_back(k);
				dp[i][k * v[i] + r] = dp[i-1][q.front() * v[i] + r] - q.front() * w[i] + k * w[i]; 
			}
		}
	}
	
	printf("%d", dp[n][m]);
	
	return 0;
}
字符串
--哈希
void init() {
	p[0] = 1;
	for (int i = 1; i <= 10000; i++) {
		p[i] = p[i-1] * P;
	}
	int len = strlen(s + 1);
	for (int i = 1; i <= len; i++) {
		hash[i] = hash[i-1] * P + s[i]; 
	}
}
unsigned long long gethash(int l, int r) {
	return hash[r] - hash[l - 1] * p[r - l + 1];
}
--KMP
void getnxt() {
	for (int i = 2, j = 0; i <= m; i++) {
		while (j && t[i] != t[j + 1]) {
			j = nxt[j];
		}
		if (t[i] == t[j + 1]) {
			j++;
		}
		nxt[i] = j;
	}
}
void kmp() {
	for (int i = 1, j = 0; i <= n; i++) {
		while (j && s[i] != t[j + 1]) {
			j = nxt[j];
		}
		if (s[i] == t[j + 1]) {
			j++;
		}
		if (j >= m) {
			printf("%d\n", i - j + 1);
		}
	}
}
--trie树
void ist(string s) {
	int p = 0;
	for (int i = 0; i < s.size(); i++) {
		if (!trie[p][s[i]]) trie[p][s[i]] = ++tot;
		p = trie[p][s[i]];
	}
	cnt[p]++;
}
int fid(string s) {
	int p = 0;
	for (int i = 0; i < s.size(); i++) {
		if (!trie[p][s[i]]) return 0;
		p = trie[p][s[i]];
	}
	return cnt[p];
}
--AC自动机

// AC自动机的dp都非常套路
//dp[i][j]表示当前在节点i,且串长为j时的情况
//有时再加一维表示这个状态里包含了哪些东西

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;
int n;
char s[N];
int trie[N][26], cnt[N], flag[N], fail[N];
int tot;
queue<int> q;
void insert(char s[]) {
	int u = 1, len = strlen(s);
	for (int i = 0; i < len; i++) {
		int v = s[i] - 'a';
		if (!trie[u][v]) trie[u][v] = ++tot;
		u = trie[u][v];
	}
	cnt[u]++;
}
void getfail() {
	for (int i = 0; i < 26; i++) trie[0][i] = 1;
	q.push(1);
	fail[1] = 0;
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = 0; i < 26; i++) {
			if (!trie[u][i]) {
				trie[u][i] = trie[fail[u]][i];
				continue;
			}
			fail[trie[u][i]] = trie[fail[u]][i];
			q.push(trie[u][i]);
		}
	}
}
int query(char s[]) {
	int u = 1, len = strlen(s), ans = 0;
	for (int i = 0; i < len; i++) {
		int v = s[i] - 'a';
		int k = trie[u][v];
		while (k > 1 && !flag[k]) {
			ans = ans + cnt[k];
			flag[k] = 1;
			k = fail[k];
		}
		u = trie[u][v];
	}
	return ans;
}
int main() {
	tot = 1;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%s", s);
		insert(s);
	}
	getfail();
	scanf("%s", s);
	printf("%d\n", query(s));
	
	return 0;
}
数据结构
--哈希表
struct hashtable {
	struct data {
		int u, v, nxt;
	};
	data e[N];
	int h[N], cnt;
	int hash(int u) {
		return (u % N + N) % N;
	}
	int query(int u) {
		int hu = hash(u);
		for (int i = h[hu]; i; i = e[i].nxt) {
			if (e[i].u == u) {
				return e[i].v;
			}
		}
		return 0;
	} 
	void update(int u, int v) {
		int hu = hash(u);
		for (int i = h[hu]; i; i = e[i].nxt) {
			if (e[i].u == u) {
				e[i].v = v;
				return;
			}
		}
		e[++cnt] = {u, v, h[hu]};
		h[hu] = cnt;
	}
};

封装:

struct hash_map {
	struct data {
		int u, v, nxt;
	};
	data e[N << 1];
	int h[N], cnt;
	int hash(int u) {
		return (u % N + N) % N;
	}
	int& operator [] (int u) {
		int hu = hash(u);
		for (int i = h[hu]; i != 0; i = e[i].nxt) {
			if (e[i].u == u) {
				return e[i].v;
			}
		}
		e[++cnt] = {u, 0, h[hu]};
		h[hu] = cnt;
		return e[cnt].v;
	}
	hash_map() {
		cnt = 0;
		memset(h, 0, sizeof(h));
	} 
};
--并查集
int fid(int x) {
	if (x != fa[x]) {
		fa[x] = fid(fa[x]);
	}
	return fa[x];
}
--可撤销并查集
// siz表示联通块内的点的数量,cnt是联通块内边的数量
int getfa(int x) {
	if (x != fa[x]) {
		return getfa(fa[x]);
	}
	return fa[x];
}
void link(int &ans, int x, int y) {
	int xf = getfa(x); xx.push(xf);
	int yf = getfa(y); yy.push(yf);
	if (xf == yf) {
		cnt[xf]++;
	} else {
		if (siz[xf] < siz[yf]) swap(xf, yf);
		siz[xf] += siz[yf];
		cnt[xf] += cnt[yf];
		cnt[xf]++;
		fa[yf] = xf;
	}
}
void cut(int &ans) {
	int tx = xx.top(); xx.pop();
	int ty = yy.top(); yy.pop();
	if (tx == ty) {
		cnt[tx]--;
	} else {
		siz[tx] -= siz[ty];
		cnt[tx] -= cnt[ty];
		cnt[tx]--;
		fa[ty] = ty;
	}
}
--单调队列
#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;
int a[N];

deque<int> q;

int main() {
	int n, k;
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	// min
	for (int i = 1; i <= n; i++) {
		while (!q.empty() && a[i] < a[q.back()]) {
			q.pop_back();
		}
		q.push_back(i);
		while (!q.empty() && q.front() < i - k + 1) {
			q.pop_front();
		}
		if (i >= k) {
			printf("%d ", a[q.front()]);
		}
	}
	printf("\n");
	
	while (!q.empty()) q.pop_back();
	// max
	for (int i = 1; i <= n; i++) {
		while (!q.empty() && a[i] > a[q.back()]) {
			q.pop_back();
		}
		q.push_back(i);
		while (!q.empty() && q.front() < i - k + 1) {
			q.pop_front();
		}
		if (i >= k) {
			printf("%d ", a[q.front()]);
		}
	}
	
	return 0;
}
--树状数组
// 极其粗糙地来凑个数
struct BIT {
	int c[N];
	int lowbit(int x) {
		return x & -x;
	}
	void update(int x, int v) {
		for (int i = x; i <= M; i += lowbit(i)) {
			c[i] += v;
		}
	}
	int query(int x) {
		int ret = 0;
		for (int i = x; i > 0; i -= lowbit(i)) {
			ret += c[i];
		}
		return ret;
	}
	int query(int l, int r) {
		return query(r) - query(l - 1);
	}
};
--线段树
----单点修改,区间查询
struct Tree {
	int l, r;
	int s;
};
Tree tree[4 * N];
void build(int p, int l, int r) {
	tree[p].l = l;
	tree[p].r = r;
	if (l == r) {
		tree[p].s = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	tree[p].s = tree[p*2].s + tree[p*2+1].s;
}
void add(int p, int x, int v) {
	if (tree[p].l == tree[p].r) {
		tree[p].s += v;
		return;
	} 
	int mid = (tree[p].l + tree[p].r) / 2;
	if (x <= mid) {
		add(p * 2, x, v);
	} else {
		add(p * 2 + 1, x, v);
	}
	tree[p].s = tree[p * 2].s + tree[p * 2 + 1].s;
}
int sum(int p, int l, int r) {
	if (l <= tree[p].l && tree[p].r <= r) {
		return tree[p].s;
	}
	int mid = (tree[p].l + tree[p].r) / 2;

	int ret = 0;
	if (l <= mid) {
		ret += sum(p * 2, l, r);
	}
	if (r > mid) {
		ret += sum(p * 2 + 1, l, r);
	}
	return ret;
}
----区间修改,单点查询
struct Tree {
	int l, r;
	long long s;
	long long lazy;
};
Tree tree[4 * N];
void build(int p, int l, int r) {
	tree[p].l = l;
	tree[p].r = r;
	if (l == r) {
		tree[p].s = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	tree[p].s = tree[p*2].s + tree[p*2+1].s;
}
void pushdown(int p) {
	int lc = p * 2;
	int rc = p * 2 + 1;
	if (tree[p].lazy && tree[p].l != tree[p].r) {
		tree[lc].lazy += tree[p].lazy;
		tree[rc].lazy += tree[p].lazy;
		tree[lc].s += tree[p].lazy * (tree[lc].r - tree[lc].l + 1);
		tree[rc].s += tree[p].lazy * (tree[rc].r - tree[rc].l + 1);
		tree[p].lazy = 0; 
	}
}
void add(int p, int l, int r, long long v) {
	pushdown(p);
	if (tree[p].l == tree[p].r) {
		tree[p].s += v;
		return;
	} 
	int lc = p * 2;
	int rc = p * 2 + 1;
	int mid = (tree[p].l + tree[p].r) / 2;
	if (r <= mid) {
		add(lc, l, r, v);
	} else if (l > mid) {
		add(rc, l, r, v);
	} else {
		add(lc, l, r, v);
		add(rc, l, r, v);
	}
	tree[p].s = tree[lc].s + tree[rc].s;
}
long long sum(int p, int x) {
	pushdown(p);
	if (tree[p].l == tree[p].r) {
		return tree[p].s;
	}
	int lc = p * 2;
	int rc = p * 2 + 1;
	int mid = (tree[p].l + tree[p].r) / 2;
	if (x <= mid) {
		return sum(lc, x);
	} else {
		return sum(rc, x);
	}
}
----区间修改,区间查询
long long n, m, a[N];
struct Tree {
	long long l, r, s, lazy;
};
Tree tree[4 * N];
void build(int p, int l, int r) {
	tree[p].l = l;
	tree[p].r = r;
	if (l == r) {
		tree[p].s = a[l];
		return;
	}
	int mid = (l + r) / 2;
	int lc = 2 * p;
	int rc = 2 * p + 1;
	build(lc, l, mid);
	build(rc, mid + 1, r);
	tree[p].s = tree[lc].s + tree[rc].s;
}
void pushdown(int p) {
	int lc = 2 * p;
	int rc = 2 * p + 1;
	if (tree[p].lazy && tree[p].l != tree[p].r) {
		tree[lc].lazy += tree[p].lazy;
		tree[rc].lazy += tree[p].lazy;
		tree[lc].s += tree[p].lazy * (tree[lc].r - tree[lc].l + 1);
		tree[rc].s += tree[p].lazy * (tree[rc].r - tree[rc].l + 1);
		tree[p].lazy = 0;
	}
}
void update(int p, int l, int r, long long v) {
	pushdown(p);
	if (l == tree[p].l && tree[p].r == r) {
		tree[p].lazy += v;
		tree[p].s += v * (tree[p].r - tree[p].l + 1);
		return;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int lc = 2 * p;
	int rc = 2 * p + 1;
	if (mid < l) {
		update(rc, l, r, v);
	} else if (r <= mid) {
		update(lc, l, r, v);
	} else {
		update(lc, l, mid, v);
		update(rc, mid + 1, r, v);
	}
	tree[p].s = tree[lc].s + tree[rc].s;
}
long long query(int p, int l, int r) {
	pushdown(p);
	if (l <= tree[p].l && tree[p].r <= r) {
		return tree[p].s;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int lc = 2 * p;
	int rc = 2 * p + 1;
	if (mid < l) {
		return query(rc, l, r);
	} else if (r <= mid) {
		return query(lc, l, r);
	} else {
		return query(lc, l, mid) + query(rc, mid + 1, r);
	}
}
----区间最值
struct node {
	int l, r, mn, lazy;
};
node tree[4 * N];
void pushdown(int p) {
	if (tree[p].lazy && tree[p].l != tree[p].r) {
		int lc = p * 2, rc = p * 2 + 1;
		tree[lc].lazy += tree[p].lazy;
		tree[rc].lazy += tree[p].lazy;
		tree[lc].mn += tree[p].lazy;
		tree[rc].mn += tree[p].lazy;
		tree[p].lazy = 0;
	}
}
void build(int p, int l, int r) {
	tree[p].l = l, tree[p].r = r;
	tree[p].lazy = 0;
	if (l == r) {
		tree[p].mn = dp[l];
		return;
	}
	int mid = (l + r) / 2;
	int lc = p * 2, rc = p * 2 + 1;
	build(lc, l, mid);
	build(rc, mid + 1, r);
	tree[p].mn = min(tree[lc].mn, tree[rc].mn);
}
void update(int p, int l, int r, int v) {
	if (l > r) return;
	pushdown(p);
	if (l == tree[p].l && tree[p].r == r) {
		tree[p].lazy += v;
		tree[p].mn += v;
		return;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int lc = 2 * p, rc = 2 * p + 1;
	if (r <= mid) {
		update(lc, l, r, v);
	} else if (l > mid) {
		update(rc, l, r, v);
	} else {
		update(lc, l, mid, v);
		update(rc, mid + 1, r, v);
	}
	tree[p].mn = min(tree[lc].mn, tree[rc].mn);
}
int query(int p, int l, int r) {
	if (l > r) return INF;
	pushdown(p);
	if (l == tree[p].l && tree[p].r == r) {
		return tree[p].mn;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int lc = 2 * p, rc = 2 * p + 1;
	if (r <= mid) {
		return query(lc, l, r);
	} else if (l > mid) {
		return query(rc, l, r);
	} else {
		return min(query(lc, l, mid), query(rc, mid + 1, r));
	}
}
----区间最大公约数
#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;
long long n, m, a[N];
struct Tree {
	long long l, r, s, g;
};
Tree tree[4 * N];

long long gcdd(long long n, long long m) {
	if (n == 0) {
		return m;
	}
	return gcdd(m % n, n);
}

void build(int p, int l, int r) {
	tree[p].l = l;
	tree[p].r = r;
	if (l == r) {
		tree[p].s = a[l] - a[l - 1];
		tree[p].g = a[l] - a[l - 1];
		return;
	}
	int mid = (l + r) / 2;
	int lc = 2 * p;
	int rc = 2 * p + 1;
	build(lc, l, mid);
	build(rc, mid + 1, r);
	tree[p].s = tree[lc].s + tree[rc].s;
	tree[p].g = gcdd(tree[lc].g, tree[rc].g);
}

void update(int p, int x, long long v) {
	if (tree[p].l == tree[p].r) {
		tree[p].s += v;
		tree[p].g += v;
		return;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int lc = 2 * p;
	int rc = 2 * p + 1;
	if (x <= mid) {
		update(lc, x, v);
	} else {
		update(rc, x, v);
	}
	tree[p].s = tree[lc].s + tree[rc].s;
	tree[p].g = gcdd(tree[lc].g, tree[rc].g);
}

Tree query(int p, int l, int r) {
	if (l <= tree[p].l && tree[p].r <= r) {
		return tree[p];
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int lc = 2 * p;
	int rc = 2 * p + 1;
	if (mid < l) {
		return query(rc, l, r);
	} else if (r <= mid) {
		return query(lc, l, r);
	} else {
		Tree ll = query(lc, l, r);
		Tree rr = query(rc, l, r);
		Tree ret;
		ret.s = ll.s + rr.s;
		ret.g = gcdd(ll.g, rr.g);
		return ret;
	}
}

int main() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
	}
	build(1, 1, n);
	while (m--) {
		char op[3];
		scanf("%s", op);
		int l, r;
		if (op[0] == 'C') {
			long long v;
			scanf("%d%d%lld", &l, &r, &v);
			update(1, l, v);
			if (r + 1 <= n) {
				update(1, r + 1, -v);
			}
		} else {
			scanf("%d%d", &l, &r);
			Tree ll = query(1, 1, l), rr;
			if (l + 1 <= r) {
				rr = query(1, l + 1, r);
			} else {
				rr = {0, 0, 0, 0};
			}
			printf("%lld\n", abs(gcdd(ll.s, rr.g))); 
		}
	}

	return 0;
}
----权值线段树
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e5 + 10;
int n, a[N], op[N], b[N];
struct node {
	int l, r, num;
};
node tree[8 * N];

void build(int p, int l, int r) {
	tree[p].l = l;
	tree[p].r = r;
	tree[p].num = 0;
	if (l == r) {
		return;
	}
	int mid = (l + r) >> 1;
	build(p * 2, l, mid);
	build(p * 2 + 1, mid + 1, r);
}

void update(int p, int x, int v) {
	if (tree[p].l == tree[p].r) {
		tree[p].num += v;
		return;
	}
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (x <= mid) {
		update(p * 2, x, v);
	} else {
		update(p * 2 + 1, x, v);
	}
	tree[p].num = tree[p * 2].num + tree[p * 2 + 1].num;
}

int rankx1(int p, int x) {
	if (tree[p].l == tree[p].r) {
		return 1;
	}
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (x <= mid) {
		return rankx1(p * 2, x);
	} else {
		return tree[p * 2].num + rankx1(p * 2 + 1, x);
	}
}

int rankx2(int p, int x) {
	if (tree[p].l == tree[p].r) {
		return tree[p].num;
	}
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (x <= mid) {
		return rankx2(p * 2, x);
	} else {
		return tree[p * 2].num + rankx2(p * 2 + 1, x);
	}
}

int kth(int p, int k) {
	if (tree[p].l == tree[p].r) {
		return tree[p].l;
	}
	if (k <= tree[p * 2].num) {
		return kth(p * 2, k);
	} else {
		return kth(p * 2 + 1, k - tree[p * 2].num);
	}
}

signed main() {
	scanf("%lld", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%lld%lld", &op[i], &a[i]);
	}
	int tot = 0;
	for (int i = 1; i <= n; i++) {
		if (op[i] != 4) {
			b[++tot] = a[i];
		}
	}
	sort(b + 1, b + 1 + tot);
	for (int i = 1; i <= n; i++) {
		if (op[i] != 4) {
			a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b;
		}
	}
	build(1, 1, tot);
	for (int i = 1; i <= n; i++) {
		if (op[i] == 1) {
			update(1, a[i], 1);
		} else if (op[i] == 2) {
			update(1, a[i], -1);
		} else if (op[i] == 3) {
			printf("%lld\n", rankx1(1, a[i]));
		} else if (op[i] == 4) {
			printf("%lld\n", b[kth(1, a[i])]);
		} else if (op[i] == 5) {
			update(1, a[i], 1);
			printf("%lld\n", b[kth(1, rankx1(1, a[i]) - 1)]);
			update(1, a[i], -1);
		} else {
			update(1, a[i], 1);
			printf("%lld\n", b[kth(1, rankx2(1, a[i]) + 1)]);
			update(1, a[i], -1);
		} 
	}
	
	return 0;
}
----动态开点线段树
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e5 + 10;
int n, m, a[N];
struct node {
	int l, r, s, lazy, lc, rc;
};
node tree[2 * N];
int tot = 1, root = 1;
void build(int &p, int l, int r) {
	if (!p) {
		p = ++tot;
	}
	tree[p].l = l;
	tree[p].r = r; 
	if (l == r) {
		tree[p].s = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(tree[p].lc, l , mid);
	build(tree[p].rc, mid + 1, r);
	tree[p].s = tree[tree[p].lc].s + tree[tree[p].rc].s;
}
void pushdown(int p) {
	if (tree[p].lazy && tree[p].l != tree[p].r) {
		if (!tree[p].lc) tree[p].lc = ++tot;
		if (!tree[p].rc) tree[p].rc = ++tot;
		tree[tree[p].lc].lazy += tree[p].lazy;
		tree[tree[p].rc].lazy += tree[p].lazy;
		tree[tree[p].lc].s += tree[p].lazy * (tree[tree[p].lc].r - tree[tree[p].lc].l + 1);
		tree[tree[p].rc].s += tree[p].lazy * (tree[tree[p].rc].r - tree[tree[p].rc].l + 1);
		tree[p].lazy = 0;
	}
}
void update(int &p, int l, int r, int v) {
	if (!p) {
		p = ++tot;
	}
	pushdown(p);
	if (l <= tree[p].l && tree[p].r <= r) {
		tree[p].lazy += v;
		tree[p].s += v * (tree[p].r - tree[p].l + 1);
		return;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	if (r <= mid) {
		update(tree[p].lc, l, r, v);
	} else if (l > mid) {
		update(tree[p].rc, l, r, v);
	} else {
		update(tree[p].lc, l, mid, v);
		update(tree[p].rc, mid + 1, r, v);
	}
	tree[p].s = tree[tree[p].lc].s + tree[tree[p].rc].s;
}
int query(int p, int l, int r) {
	if (!p) {
		return 0;
	}
	pushdown(p);
	if (l <= tree[p].l && tree[p].r <= r) {
		return tree[p].s;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	if (r <= mid) {
		return query(tree[p].lc, l, r);
	} else if (l > mid) {
		return query(tree[p].rc, l , r);
	} else {
		return query(tree[p].lc, l, mid) + query(tree[p].rc, mid + 1, r);
	}
}

signed main() {
	for (int i = 0; i < N; i++) {
		tree[i].lc = tree[i].rc = 0;
	}
	scanf("%lld%lld", &n, &m); 
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]); 
	}
	build(root, 1, n);
	while (m--) {
		int op, x, y, k;
		scanf("%lld%lld%lld", &op, &x, &y);
		if (op == 1) {
			scanf("%lld", &k);
			update(root, x, y, k);
		} else {
			printf("%lld\n", query(1, x, y));
		}
	}
	
	return 0;
}
----线段树合并
void merge(int &a, int b) {
	if (!a) {
		a = b;
		return;
	}
	if (!b) {
		return;
	}
	tree[a].num += tree[b].num;
	merge(tree[a].lc, tree[b].lc);
	merge(tree[a].rc, tree[b].rc);
}
----标记永久化
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e5 + 10;
int n, m, a[N];
struct node {
	int s, mark, lc, rc;
};
node tree[2 * N];
int tot = 0, root = 0;
void update(int &p, int l, int r, int x, int y, int v) {
	if (!p) p = ++tot; 
	tree[p].s += v * (y - x + 1);
	if (x == l && r == y) {
		tree[p].mark += v;
		return;
	}
	int mid = (l + r) / 2;
	if (y <= mid) {
		update(tree[p].lc, l, mid, x, y, v);
	} else if (x > mid) {
		update(tree[p].rc, mid + 1, r, x, y, v);
	} else {
		update(tree[p].lc, l, mid, x, mid, v);
		update(tree[p].rc, mid + 1, r, mid + 1, y, v);
	}
}
int query(int p, int l, int r, int x, int y, int ad) {
	if (!p) return 0;
	if (x == l && r == y) {
		return tree[p].s + ad * (y - x + 1);
	} 
	int mid = (l + r) / 2;
	if (y <= mid) {
		return query(tree[p].lc, l, mid, x, y, ad + tree[p].mark);
	} else if (x > mid) {
		return query(tree[p].rc, mid + 1, r, x, y, ad + tree[p].mark);
	} else {
		return query(tree[p].lc, l, mid, x, mid, ad + tree[p].mark) 
			 + query(tree[p].rc, mid + 1, r, mid + 1, y, ad + tree[p].mark);
	}
}
signed main() {
	scanf("%lld%lld", &n, &m); 
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]); 
		update(root, 1, n, i, i, a[i]);
	}
	while (m--) {
		int op, x, y, k;
		scanf("%lld%lld%lld", &op, &x, &y);
		if (op == 1) {
			scanf("%lld", &k);
			update(root, 1, n, x, y, k);
		} else {
			printf("%lld\n", query(root, 1, n, x, y, 0));
		}
	}
	
	return 0;
}
--分块
----区间修改区间求和
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e5 + 10;
int n, m;
int a[N], st[N], ed[N], bel[N], sum[N], mark[N], siz[N];
void init() {
	int sq = sqrt(n);
	for (int i = 1; i <= sq; i++) {
		st[i] = n / sq * (i - 1) + 1;
		ed[i] = n / sq * i;
	} 
	ed[sq] = n;
	for (int i = 1; i <= sq; i++) {
		siz[i] = ed[i] - st[i] + 1; 
	} 
	for (int i = 1; i <= sq; i++) {
		for (int j = st[i]; j <= ed[i]; j++) {
			bel[j] = i;
			sum[i] += a[j];
		}
	}
}
void update(int x, int y, int v) {
	if (bel[x] == bel[y]) {
		for (int i = x; i <= y; i++) {
			a[i] += v;
			sum[bel[i]] += v;
		}
	} else {
		for (int i = x; i <= ed[bel[x]]; i++) {
			a[i] += v;
			sum[bel[i]] += v;
		}
		for (int i = st[bel[y]]; i <= y; i++) {
			a[i] += v;
			sum[bel[i]] += v;
		}
		for (int i = bel[x] + 1; i < bel[y]; i++) {
			mark[i] += v;
		}
	}
}
int query(int x, int y) {
	int ans = 0;
	if (bel[x] == bel[y]) {
		for (int i = x; i <= y; i++) {
			ans += a[i] + mark[bel[i]];
		}
	} else {
		for (int i = x; i <= ed[bel[x]]; i++) {
			ans += a[i] + mark[bel[i]];
		}
		for (int i = st[bel[y]]; i <= y; i++) {
			ans += a[i] + mark[bel[i]];
		}
		for (int i = bel[x] + 1; i < bel[y]; i++) {
			ans += sum[i] + mark[i] * siz[i];
		}
	}
	return ans;
}
signed main() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
	}
	init();
	while (m--) {
		int op;
		scanf("%lld", &op);
		if (op == 1) {
			int x, y, k;
			scanf("%lld%lld%lld", &x, &y, &k);
			update(x, y, k);
		} else {
			int x, y;
			scanf("%lld%lld", &x, &y);
			printf("%lld\n", query(x, y));
		}
	} 
	
	return 0;
}
----区间修改区间求大于/小于/大于等于/小于等于
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e6 + 10;
int n, q, a[N], d[N];
int st[N], ed[N], bel[N], mark[N];
void init() {
	int sq = sqrt(n);
	for (int i = 1; i <= sq; i++) {
		st[i] = n / sq * (i - 1) + 1;
		ed[i] = n / sq * i;
	}
	ed[sq] = n;
	for (int i = 1; i <= sq; i++) {
		for (int j = st[i]; j <= ed[i]; j++) {
			bel[j] = i;
		}
	}
	for (int i = 1; i <= n; i++) {
		d[i] = a[i];
	}
	for (int i = 1; i <= sq; i++) {
		sort(d + st[i], d + ed[i] + 1);
	}
}
void update(int x, int y, int v) {
	if (bel[x] == bel[y]) {
		for (int i = x; i <= y; i++) {
			a[i] += v;
		}
		for (int i = st[bel[x]]; i <= ed[bel[x]]; i++) {
			d[i] = a[i];
		}
		sort(d + st[bel[x]], d + ed[bel[x]] + 1);
		return;
	}
	for (int i = x; i <= ed[bel[x]]; i++) {
		a[i] += v;
	}
	for (int i = st[bel[x]]; i <= ed[bel[x]]; i++) {
		d[i] = a[i];
	}
	sort(d + st[bel[x]], d + ed[bel[x]] + 1);
	for (int i = st[bel[y]]; i <= y; i++) {
		a[i] += v;
	} 
	for (int i = st[bel[y]]; i <= ed[bel[y]]; i++) {
		d[i] = a[i];
	}
	sort(d + st[bel[y]], d + ed[bel[y]] + 1);
	for (int i = bel[x] + 1; i < bel[y]; i++) {
		mark[i] += v;
	}
}
int query(int x, int y, int v) {
	int ans = 0;
	if (bel[x] == bel[y]) {
		for (int i = x; i <= y; i++) {
			if (a[i] + mark[bel[i]] >= v) {
				ans++;
			}
		}
		return ans;
	}
	for (int i = x; i <= ed[bel[x]]; i++) {
		if (a[i] + mark[bel[i]] >= v) {
			ans++;
		}
	}
	for (int i = st[bel[y]]; i <= y; i++) {
		if (a[i] + mark[bel[i]] >= v) {
			ans++;
		}
	}
	for (int i = bel[x] + 1; i < bel[y]; i++) {
		int l = st[i], r = ed[i], ret = 0;
		while (l <= r) {
			int mid = (l + r) / 2;
			if (d[mid] + mark[i] >= v) {
				ret = mid;
				r = mid - 1;
			} else {
				l = mid + 1;
			}
		}
		if (ret != 0) {
			ans = ans + (ed[i] - ret + 1);
		}
	}
	return ans;
}
signed main() {
	scanf("%lld%lld", &n, &q);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
	}
	init();
	while (q--) {
		char op[3];
		int l, r, w;
		scanf("%s%lld%lld%lld", op, &l, &r, &w);
		if (op[0] == 'M') {
			update(l, r, w);
		} else {
			printf("%lld\n", query(l, r, w));
		}
	}
	
	return 0;
}
--ST表
#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10, M = 18;
int Log2[N];
int f[N][M]; // f[i][j] 表示区间  [i, 2^(j-1)-1] 的最大值 
int n, m, a[N];
void init() {
	for (int i = 2; i <= n; i++) Log2[i] = Log2[i / 2] + 1;
	for (int i = 1; i <= n; i++) f[i][0] = a[i];
	for (int j = 1; j <= Log2[n]; j++) {
		for (int i = 1; i + (1 << j) - 1 <= n; i++) {
			f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]); // ST表具体实现 
		}
	}
}
int query(int l, int r) {
	int s = Log2[r - l + 1];
	return max(f[l][s], f[r - (1 << s) + 1][s]);
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	init();
	while (m--) {
		int l, r;
		scanf("%d%d", &l, &r);
		printf("%d\n", query(l, r));
	}
	
	return 0;
}
--平衡树
----FHQ-Treap
#include <bits/stdc++.h>

using namespace std;

mt19937 wdz(time(0));

const int N = 1e5 + 10;
int tot, root;
struct FHQ_Treap {
    int l, r, val, key, siz;
} tr[N];
#define lc tr[p].l
#define rc tr[p].r
void update(int p) { // 更新 p 的子树大小 
	tr[p].siz = tr[lc].siz + tr[rc].siz + 1;
}
void create(int &p, int x) { // 新建一棵只有一个节点的 Treap 
	p = ++tot;
	tr[p].val = x;
	tr[p].key = wdz();
	tr[p].siz = 1;
}
void split(int p, int k, int &x, int &y) {
	// 根节点,关键值,以及分裂后的两个节点 
	if (!p) {
		x = y = 0;
		return;
	}
	if (tr[p].val <= k) { // 权值小于等于 k 
		x = p; // 左子树全部属于第一个子树 
		split(rc, k, rc, y); // 分裂右子树 
	} else {
		y = p;
		split(lc, k, x, lc);
	}
	update(p);
}
int merge(int x, int y) { // 返回合并后的树根 
	if (!x || !y) {
		return x + y;
	}
	if (tr[x].key < tr[y].key) { // x 的优先级小于 y 的优先级 
		tr[x].r = merge(tr[x].r, y);
		// 将子树 y 并入子树 x 的右子树 
		update(x);
		return x;
	} else {
		tr[y].l = merge(x, tr[y].l);
		update(y);
		return y;
	}
}
int kth(int p, int k) { // 查询在 p 及其子树中排名为 k 的数 
	if (k == tr[lc].siz + 1) { // 为当前节点 
		return tr[p].val;
	}
	if (k <= tr[lc].siz) { // 在左子树中 
		return kth(lc, k);
	} else { // 在右子树中 
		return kth(rc, k - tr[lc].siz - 1);
	}
}
int qq;
int now, tmp, x, y;
int main() {
	scanf("%d", &qq);
	while (qq--) {
		int op, k;
		scanf("%d%d", &op, &k);
		if (op == 1) { 
			// 插入 k 
			split(root, k, x, y); 
			create(now, k);
			root = merge(merge(x, now), y);
		} else if (op == 2) { 
			// 删除 k 
			split(root, k, x, tmp);
			split(x, k - 1, x, y);
			// 分离子树 
			y = merge(tr[y].l, tr[y].r);
			// 合并 x 的子树,也就是去掉 x 
			root = merge(merge(x, y), tmp);
		} else if (op == 3) { 
			// 查询 k 数的排名 
			split(root, k - 1, x, y); // 分离子树 
			printf("%d\n", tr[x].siz + 1); // 节点数即为排名 
			root = merge(x, y);
		} else if (op == 4) { 
			// 查询排名为 k 的数 
			printf("%d\n", kth(root, k));
		} else if (op == 5) { 
			// 前驱 
			split(root, k - 1, x, y);
			printf("%d\n", kth(x, tr[x].siz));
			root = merge(x, y); 
		} else { 
			// 后继 
			split(root, k, x, y);
			printf("%d\n", kth(y, 1));
			root = merge(x, y);
		}
	}
	
	return 0;
}
图论
--tarjan
----强联通分量
vector<int> G[N];
int dfn[N], low[N], inst[N], scc[N], siz[N];
stack<int> st;
int tot = 0, cnt = 0;

void tarjan(int x) {
	dfn[x] = low[x] = ++tot;
	inst[x] = 1;
	st.push(x);
	for (int y : G[x]) {
		if (dfn[y] == 0) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		} else if (inst[y] == 1) {
			low[x] = min(low[x], dfn[y]);
		}
	}
	if (low[x] == dfn[x]) {
		int y;
		cnt++;
		while (true) {
			y = st.top();
			st.pop();
			inst[y] = 0;
			scc[y] = cnt;
			siz[cnt]++;
			if (x == y) {
				break;
			}
		}
	}
}
----缩点

同上,略

----割点
int n;
vector<int> G[N];
int dfn[N], low[N], ans[N];
int tot = 0;
void tarjan(int x, int fa) {
	int son = 0;
	low[x] = dfn[x] = ++tot;
	for (int y : G[x]) {
		if (dfn[y] == 0) {
			son++;
			tarjan(y, x);
			low[x] = min(low[x], low[y]);
			if (low[y] >= dfn[x]) {
				ans[x] = 1;
			}
		} else if (y != fa) {
			low[x] = min(low[x], dfn[y]);
		}
	}
	if (fa == 0 && son < 2) {
		ans[x] = 0;
	}
}
----割边
int n, m;
vector<int> G[N];
int dfn[N], low[N], ans[N][N];
int tot = 0;
void tarjan(int x, int fa) {
	low[x] = dfn[x] = ++tot;
	for (int y : G[x]) {
		if (dfn[y] == 0) {
			tarjan(y, x);
			low[x] = min(low[x], low[y]);
			if (low[y] > dfn[x]) {
				ans[x][y] = ans[y][x] = 1;
			}
		} else if (y != fa) {
			low[x] = min(low[x], dfn[y]);
		}
	}
}
----点双
#include <bits/stdc++.h>

using namespace std;

const int N = 300 + 10;
int n, m;
vector<int> G[N];
int dfn[N], low[N];
stack<int> st;
vector<int> dcc[N];
int cnt = 0;
int tot = 0;
void tarjan(int x, int fa) {
	low[x] = dfn[x] = ++tot;
	st.push(x);
	if (fa == 0 && G[x].size() == 0) {
		dcc[++cnt].push_back(x);
		return;
	}
	for (int y : G[x]) {
		if (dfn[y] == 0) {
			tarjan(y, x);
			low[x] = min(low[x], low[y]);
			if (low[y] >= dfn[x]) {
				cnt++;
				while (true) {
					int z = st.top();
					st.pop();
					dcc[cnt].push_back(z);
					if (y == z) {
						break;
					}
				}
				dcc[cnt].push_back(x);
			}
		} else if (y != fa) {
			low[x] = min(low[x], dfn[y]);
		}
	}
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		if (x != y) {
			G[x].push_back(y);
			G[y].push_back(x);
		}
	} 

	for (int i = 1; i <= n; i++) {
		if (dfn[i] == 0) {
			tarjan(i, 0);
		}
	}

	printf("%d\n", cnt);
	for (int i = 1; i <= cnt; i++) {
		printf("%d ", dcc[i].size());
		for (int x : dcc[i]) {
			printf("%d ", x); 
		} 
		printf("\n");
	}

	return 0;
}
----边双
#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;
int n, m;
vector<int> G[N];
int dfn[N], low[N];
stack<int> st;
vector<int> dcc[N];
int cnt = 0;
int tot = 0;
void tarjan(int x, int fa) {
	low[x] = dfn[x] = ++tot;
	st.push(x);
	for (int y : G[x]) {
		if (dfn[y] == 0) {
			tarjan(y, x);
			low[x] = min(low[x], low[y]);
			if (low[y] > dfn[x]) {
	
			}
		} else if (y != fa) {
			low[x] = min(low[x], dfn[y]);
		}
	}
	if (dfn[x] == low[x]) {
		cnt++;
		while (true) {
			int y = st.top();
			st.pop();
			dcc[cnt].push_back(y);
			if (x == y) {
				break;
			}
		}
	}
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		if (x != y) {
			G[x].push_back(y);
			G[y].push_back(x);
		}
	} 

	for (int i = 1; i <= n; i++) {
		if (dfn[i] == 0) {
			tarjan(i, 0);
		}
	}

	printf("%d\n", cnt);
	for (int i = 1; i <= cnt; i++) {
		printf("%d ", dcc[i].size());
		for (int x : dcc[i]) {
			printf("%d ", x); 
		} 
		printf("\n");
	}

	return 0;
}
--lca
void dfs(int x, int father) {
	dep[x] = dep[father] + 1;
	fa[x][0] = father;
	for (int i = 1; i <= 19; i++) {
		fa[x][i] = fa[fa[x][i-1]][i-1];
	}
	for (int y : G[x]) {
		if (y != father) {
			dfs(y, x);
		}
	}
}
int lca(int x, int y) {
	if (dep[x] < dep[y]) {
		swap(x, y);
	}
	for (int i = 19; i >= 0; i--) {
		if (dep[fa[x][i]] >= dep[y]) {
			x = fa[x][i];
		}
	}
	if (x == y) {
		return y;
	}
	for (int i = 19; i >= 0; i--) {
		if (fa[x][i] != fa[y][i]) {
			x = fa[x][i];
			y = fa[y][i];
		}
	}
	return fa[x][0];
}
--prim
vector<int> G[N];
int w[N][N], dis[N], vis[N];
struct node {
	int x, d;
	bool operator < (const node &cmp) const {
		return d > cmp.d;
	}
};
priority_queue<node> q;
int ans = 0;
void prim() {
	dis[1] = 0;
	node tmp;
	tmp.x = 1;
	tmp.d = 0;
	q.push(tmp);
	int cnt = 0;
	while (!q.empty()) {
		node f = q.top();
		q.pop();
		int x = f.x;
		if (f.d > dis[x]) {
			continue;
		}
		cnt++;
		ans += f.d;
		dis[x] = 1;
		for (int y : G[x]) {
			if (vis[y] == 0 && w[x][y] < dis[y]) {
				dis[y] = w[x][y];
				node t;
				t.x = y;
				t.d = dis[y];
				q.push(t);
			}
		}
	}
	if (cnt < n) ans = -1;
}
int main() {
	memset(w, INF, sizeof(w));
	memset(dis, INF, sizeof(dis));
	return 0;
}
--kruskal
#include <bits/stdc++.h>

using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 5e3 + 10, M = 2e5 + 10;
int n, m;
struct edge {
	int x, y, w;
};
edge e[M];
int fa[N];
int fid(int x) {
	if (x != fa[x]) {
		fa[x] = fid(fa[x]);
	}
	return fa[x];
}
bool cmp(edge a, edge b) {
	return a.w < b.w;
}
int ans = 0;
void kruskal() {
	int cnt = 0;
	sort(e + 1, e + 1 + m, cmp);
	for (int i = 1; i <= m; i++) {
		int x = fid(e[i].x);
		int y = fid(e[i].y);
		if (x == y) continue;
		ans += e[i].w;
		fa[y] = x;
		cnt++;
		if (cnt == n - 1) {
			return;
		}
	}
	ans = -1;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) fa[i] = i;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].w);
	}
	
	kruskal();
	
	if (ans == -1) {
		printf("orz\n"); 
	} else {
		printf("%d\n", ans);
	}
	
	return 0;
}
--dijkstra
struct edge {
	int y, w, id;
}; 
vector<edge> G[N]; 
int dis[N], pre[N];
struct node {
	int x, d;
	bool operator < (const node & cmp) const {
		return d > cmp.d;
	}
};
priority_queue<node> q;
void dijkstra() {
	for (int i = 2; i <= n; i++) dis[i] = INF, pre[i] = 0;
	q.push({1, 0});
	while (!q.empty()) {
		node f = q.top(); q.pop();
		if (f.d > dis[f.x]) continue;
		for (edge i : G[f.x]) {
			if (dis[i.y] > f.d + i.w) {
				dis[i.y] = f.d + i.w;
				pre[i.y] = i.id;
				q.push({i.y, dis[i.y]});
			}
		}
	}
}
--拓补排序
// 直接复制的OI-WIKI上的,懒得打了
bool toposort() {
  vector<int> L;
  queue<int> S;
  for (int i = 1; i <= n; i++)
    if (in[i] == 0) S.push(i);
  while (!S.empty()) {
    int u = S.front();
    S.pop();
    L.push_back(u);
    for (auto v : G[u]) {
      if (--in[v] == 0) {
        S.push(v);
      }
    }
  }
  if (L.size() == n) {
    for (auto i : L) cout << i << ' ';
    return true;
  } else {
    return false;
  }
}
--树链剖分
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e5 + 10;
int n, m, rt, MOD;
vector<int> G[N];
int w[N], fa[N], dep[N], siz[N], son[N], id[N], rk[N], top[N];
int cnt = 0;
void dfs1(int x, int father) {
	fa[x] = father;
	dep[x] = dep[father] + 1;
	siz[x] = 1;
	for (int y : G[x]) {
		if (y != father) {
			dfs1(y, x);
			siz[x] += siz[y];
			if (siz[y] > siz[son[x]]) {
				son[x] = y;
			}
		}
	}
}
void dfs2(int x, int t) {
	id[x] = ++cnt;
	rk[cnt] = x;
	top[x] = t;
	if (son[x] == 0) return;
	dfs2(son[x], t);
	for (int y : G[x]) {
		if (y != fa[x] && y != son[x]) {
			dfs2(y, y);
		}
	}
}
struct node {
	int l, r, sum, lazy;
};
node tree[4 * N];
void build(int p, int l, int r) {
	tree[p].l = l, tree[p].r = r;
	tree[p].lazy = 0;
	if (l == r) {
		tree[p].sum = w[rk[l]];
		return;
	}
	int mid = (l + r) / 2;
	int lc = p * 2, rc = p * 2 + 1;
	build(lc, l, mid);
	build(rc, mid + 1, r);
	tree[p].sum = tree[lc].sum + tree[rc].sum; 
}
void pushdown(int p) {
	if (tree[p].lazy && tree[p].l != tree[p].r) {
		int lc = p * 2, rc = p * 2 + 1;
		tree[lc].lazy += tree[p].lazy;
		tree[rc].lazy += tree[p].lazy;
		tree[lc].sum += tree[p].lazy * (tree[lc].r - tree[lc].l + 1);
		tree[rc].sum += tree[p].lazy * (tree[rc].r - tree[rc].l + 1);
		tree[p].lazy = 0;
	}
}
void update(int p, int l, int r, int v) {
	pushdown(p);
	if (l == tree[p].l && tree[p].r == r) {
		tree[p].sum += v * (r - l + 1);
		tree[p].lazy += v;
		return;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int lc = p * 2, rc = p * 2 + 1;
	if (r <= mid) {
		update(lc, l, r, v);
	} else if (l > mid) {
		update(rc, l, r, v);
	} else {
		update(lc, l, mid, v);
		update(rc, mid + 1, r, v);
	}
	tree[p].sum = tree[lc].sum + tree[rc].sum;
}
void update_path(int x, int y, int v) {
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		update(1, id[top[x]], id[x], v);
		x = fa[top[x]];
	}
	if (dep[x] < dep[y]) swap(x, y);
	update(1, id[y], id[x], v);
}
void update_tree(int x, int v) {
	update(1, id[x], id[x] + siz[x] - 1, v);
}
int query(int p, int l, int r) {
	pushdown(p);
	if (l == tree[p].l && tree[p].r == r) {
		return tree[p].sum;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int lc = p * 2, rc = p * 2 + 1;
	if (r <= mid) {
		return query(lc, l, r);
	} else if (l > mid) {
		return query(rc, l, r);
	} else {
		return query(lc, l, mid) + query(rc, mid + 1, r);
	}
}
int query_path(int x, int y) {
	int ret = 0;
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		ret += query(1, id[top[x]], id[x]);
		x = fa[top[x]];
	}
	if (dep[x] < dep[y]) swap(x, y);
	ret += query(1, id[y], id[x]);
	return ret;
}
int query_tree(int x) {
	return query(1, id[x], id[x] + siz[x] - 1);
}
signed main() {
	scanf("%lld%lld%lld%lld", &n, &m, &rt, &MOD);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &w[i]);
	}
	for (int i = 1; i < n; i++) {
		int x, y;
		scanf("%lld%lld", &x, &y);
		G[x].push_back(y);
		G[y].push_back(x); 
	}
	dfs1(rt, 0);
	dfs2(rt, rt);
	build(1, 1, n);
	while (m--) {
		int op;
		scanf("%lld", &op);
		if (op == 1) {
			int x, y, z;
			scanf("%lld%lld%lld", &x, &y, &z);
			update_path(x, y, z);
		} else if (op == 2) {
			int x, y;
			scanf("%lld%lld", &x, &y);
			printf("%lld\n", query_path(x, y) % MOD);
		} else if (op == 3) {
			int x, z;
			scanf("%lld%lld", &x, &z);
			update_tree(x, z);
		} else {
			int x;
			scanf("%lld", &x);
			printf("%lld\n", query_tree(x) % MOD);
		}
	}
	
	return 0;
}
--树的直径
void dfs1(int x, int fa, int flag) {
	dis[x] = dis[fa] + 1;
	if (!flag) 
		u = dis[x] > dis[u] ? x : u;
	else {
		v = dis[x] > dis[v] ? x : v;
		pre[x] = fa;
	}
	for (int y : G[x]) {
		if (y == fa) dfs1(y, x);
	}
}
杂项
--快读
char buf[1 << 20], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++)
int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') {
			f = -1;
		}
		ch = getchar();
	}
	while ('0' <= ch && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}
--快写
void write(int x) {
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
--离散化
for (int i = 1; i <= n; i++) {
	scanf("%lld", &a[i]);
	b[i] = a[i];
}
sort(b + 1, b + 1 + n);
int ll = unique(b + 1, b + 1 + n) - (b + 1);
for (int i = 1; i <= n; i++) {
	a[i] = lower_bound(b + 1, b + 1 + ll, a[i]) - b;
}
--莫队
----普通莫队
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 5e4 + 10;
int n, m, k, block, bel[N], a[N], t[N], ans[N], l, r, num;
struct node {
	int l, r, id;
};
node modui[N];
bool cmp(node a, node b) {
	if ((a.l - 1) / block != (b.l - 1) / block) {
		return (a.l - 1) / block < (b.l - 1) / block;
	}
	return a.r < b.r;
}
void add(int i) {
	num = num + 2 * t[a[i]] + 1;
	t[a[i]]++;
}
void del(int i) {
	num = num - 2 * t[a[i]] + 1;
	t[a[i]]--;
}
signed main() {
	scanf("%lld%lld%lld", &n, &m, &k);
	block = sqrt(n);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
	}
	for (int i = 1; i <= m; i++) {
		scanf("%lld%lld", &modui[i].l, &modui[i].r);
		modui[i].id = i;
	}
	sort(modui + 1, modui + 1 + m, cmp);
	l = 1, r = 0, num = 0;
	for (int i = 1; i <= m; i++) {
		while (l > modui[i].l) l--, add(l);
		while (r < modui[i].r) r++, add(r);
		while (l < modui[i].l) del(l), l++;
		while (r > modui[i].r) del(r), r--;
		ans[modui[i].id] = num;
	}
	for (int i = 1; i <= m; i++) {
		printf("%lld\n", ans[i]);
	}
	return 0;
}
----带修莫队
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e6 + 10;
int n, m, a[N], block, qcnt, rcnt, l, r, num, last, t[N], ans[N];
char op[3];
struct qnode {
	int l, r, t, id;
} q[N];
struct rnode {
	int p, x;
} c[N];
bool cmp(qnode a, qnode b) {
	if ((a.l - 1) / block != (b.l - 1) / block) {
		return (a.l - 1) / block < (b.l - 1) / block;
	}
	if ((a.r - 1) / block != (b.r - 1) / block) {
		return (a.r - 1) / block < (b.r - 1) / block;
	}
	return a.t < b.t;
}
void add(int x) {
	if (t[x] == 0) num++;
	t[x]++;
}
void del(int x) {
	t[x]--;
	if (t[x] == 0) num--;
}
signed main() {
	scanf("%lld%lld", &n, &m);
	block = pow(n, 2 / 3.0);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
	}
	for (int i = 1; i <= m; i++) {
		int x, y;
		scanf("%s%lld%lld", op, &x, &y);
		if (op[0] == 'Q') {
			q[++qcnt] = {x, y, rcnt, qcnt};
		} else {
			c[++rcnt] = {x, y};
		}
	}
	sort(q + 1, q + 1 + qcnt, cmp);
	l = 1, r = 0, num = 0, last = 0;
	for (int i = 1; i <= qcnt; i++) {
		while (l > q[i].l) l--, add(a[l]);
		while (r < q[i].r) r++, add(a[r]);
		while (l < q[i].l) del(a[l]), l++;
		while (r > q[i].r) del(a[r]), r--;
		while (last < q[i].t) {
			last++;
			if (q[i].l <= c[last].p && c[last].p <= q[i].r) {
				del(a[c[last].p]);
				add(c[last].x);
			}
			swap(a[c[last].p], c[last].x);
		}
		while (last > q[i].t) {
			if (q[i].l <= c[last].p && c[last].p <= q[i].r) {
				del(a[c[last].p]);
				add(c[last].x);
			}
			swap(a[c[last].p], c[last].x);
			last--;
		}
		ans[q[i].id] = num;
	}
	for (int i = 1; i <= qcnt; i++) {
		printf("%lld\n", ans[i]);
	}
	
	return 0;
}
----回滚莫队
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e5 + 10;
int n, q, a[N], b[N], bel[N], st[N], ed[N], l, r, t[N], mp[N], ans[N], last, num;
struct node {
	int l, r, id;
}; 
node modui[N];
bool cmp(node a, node b) {
	if (bel[a.l] != bel[b.l]) {
		return bel[a.l] < bel[b.l];
	}
	return a.r < b.r;
}
void add(int x) {
	t[x]++;
	if (b[x] * t[x] > num) {
		num = b[x] * t[x];
	}
}
signed main() {
	scanf("%lld%lld", &n, &q);
	int sq = sqrt(n);
	for (int i = 1; i <= sq; i++) {
		st[i] = n / sq * (i - 1) + 1;
		ed[i] = n / sq * i;
	}
	ed[sq] = n;
	for (int i = 1; i <= sq; i++) {
		for (int j = st[i]; j <= ed[i]; j++) {
			bel[j] = i;
		}
	}
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
		b[i] = a[i];
	}
	sort(b + 1, b + 1 + n);
	int m = unique(b + 1, b + 1 + n) - b - 1;
	for (int i = 1; i <= n; i++) {
		a[i] = lower_bound(b + 1, b + 1 + m, a[i]) - b;
	}
	for (int i = 1; i <= q; i++) {
		scanf("%lld%lld", &modui[i].l, &modui[i].r);
		modui[i].id = i;
	}
	sort(modui + 1, modui + 1 + q, cmp);
	l = 1, r = 0, last = 0;
	for (int i = 1; i <= q; i++) {
		if (bel[modui[i].l] == bel[modui[i].r]) {
			for (int j = modui[i].l; j <= modui[i].r; j++) {
				mp[a[j]]++;
			}
			int mx = 0;
			for (int j = modui[i].l; j <= modui[i].r; j++) {
				if (b[a[j]] * mp[a[j]] > mx) {
					mx = b[a[j]] * mp[a[j]];
				}
				mp[a[j]] = 0;
			}
			ans[modui[i].id] = mx;
			continue;
		}
		if (bel[modui[i].l] != last) {
			while (r > ed[bel[modui[i].l]]) t[a[r]]--, r--;
			while (l < ed[bel[modui[i].l]] + 1) t[a[l]]--, l++;
			num = 0;
			last = bel[modui[i].l]; 
		}
		int tmpl = l;
		while (r < modui[i].r) r++, add(a[r]);
		int tmp = num;
		while (l > modui[i].l) l--, add(a[l]);
		ans[modui[i].id] = num;
		num = tmp;
		while (l < tmpl) t[a[l]]--, l++;
	}
	for (int i = 1; i <= q; i++) {
		printf("%lld\n", ans[i]);
	}
	return 0;
}
--CDQ分治
void cdq(int l, int r) {
	if(l == r) return ;
	int mid = (l + r) >> 1;
	cdq(l, mid);
	cdq(mid + 1, r);
	int pl = l, pr = mid + 1;
	for(int i = l; i <= r; i++) {
		if((p[pl].y <= p[pr].y && pl <= mid) || (pr > r)) {
			b[i] = p[pl++];
		}
		else {
			p[pr].num += pl - l;
			b[i] = p[pr++];
		}
	}
	for(int i = l; i <= r; i++) {
		p[i] = b[i];
	}
}
--高维前缀和
for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++)
        for(int k = 1; k <= n; k++) 
            a[i][j][k] += a[i - 1][j][k];
for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++)
        for(int k = 1; k <= n; k++)
            a[i][j][k] += a[i][j - 1][k];
for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++)
        for(int k = 1; k <= n; k++)
            a[i][j][k] += a[i][j][k - 1];

后记

就是数学那块加了一些公式之类的,以及整体的格式进行了更改,看起来更加规整。

posted @ 2025-03-09 15:57  Zctf1088  阅读(51)  评论(1)    收藏  举报