各大算法&&数据结构模板
yizimi远欣
2018-07-20 19:50:06
## yizimi在ACM和复习用的板子
一两年前的代码,仅供参考,可能会有很多错误或者被卡常的情况(比如点分治部分)
luogu blog观感可能不太好,推荐这个:
https://blog.nowcoder.net/n/a8c81d204dd9430a99ad053ff28b530d
**特别感谢Rhein_E对模板的大量补充**
#### 更新日志(从2020.10.25 -- |)
2021.03.09 补充了Rhein_E的模板
2021.02.22 更新了数论->Miller-Rabin
2021.02.22 更新了数论->Pollard-Rho(未卡常版)
2021.02.22 补更了数据结构->珂朵莉树(ODT)
2021.02.06 更新了其他->网络流->网络最大流->预流推进HLPP
2021.02.04 更新了图论->割点(割顶)
2020.12.28 优化和完善目录
2020.12.28 优化了代码,删去多余头文件,简化长度
2020.12.28 更新了数论->高斯消元
**未完待续**
#### 注意:
本板子库常见define和头文件:
```cpp
// 循环
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
// #define rep(i, x) for(int i = h[x]; i != -1; i = e[i].nxt) 后来版本一般采用此种写法
// #define curep(i, x) for(int i = cur[x]; i != -1; i = e[i].nxt) 在Dinic中所用残留网络写法
#define mn // 数组
#define inf 1 << 30
#define llinf 1ll << 60
#define ll long long
// 线段树常用
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define root 1, n, 1
#define bson l, r, rt
#define mod // 模数
inline int read() { // 快读,如需 long long 版会说明
int x = 0, f = 1; char ch = getchar();
while(ch > '9' || ch < '0') { if(ch == '-') f = -f; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
```
目录
一.数论
1.[快速幂](#1.01)
2.[欧拉函数](#1.02)
3.[乘法逆元(线性求逆)](#1.03)
4.[线性筛素数](#1.04)
5.[扩展欧几里得](#1.05)
6.[费马小定理](#1.06)
7.[矩阵加速](#1.07)
8.[整除分块](#1.08)
9.[博弈论](#1.09)
(1)[nim游戏](#1.09.1)
10.[高斯消元](#1.10)
11.[Miller-Rabin](#1.11)
12.[Pollard-Rho(未卡常版)](#1.12)
13.[FFT](#1.13)
(1)[FFT-iterative](#1.13.01)
(2)[FFT-recursive](#1.13.02)
14.[线性异或方程组(Linear_Xor_Equation_Set)(Online)](#1.14)
15.[线性递归(Linear_Recursion)](#1.15)
16.[NTT](#1.16)
(1)[NTT-iterative](#1.16.01)
二.图论
1.[并查集](#2.01)
2.[Kruskal算法](#2.02)
3.[Dijkstra算法(优化版)](#2.03)
4.[SPFA算法](#2.04)
5.[Floyd(已优化)](#2.05)
6.[二分图染色](#2.06)
7.[拓扑排序](#2.07)
8.[缩点(tarjan求强联通分量)](#2.08)
9.[割点(割顶)](#2.09)
10.[树分治](#2.10)
(1)[点分治](#2.10.1)
11.网络流
(一)网络最大流
(1)[EK算法](#2.11.01.1)
(2)[Dinic算法](#2.11.01.2)
(3)[预流推进HLPP](#2.11.01.3)
(二)最小费用最大流
(1)[SPFA版](#2.11.02.1)
(2)[Dijkstra版](#2.11.02.2)
12.[树链剖分](#2.12)
13.[Prim](#2.13)
三.数据结构
1.[堆](#3.01)
2.[线段树](#3.02)
3.[(ex_线段树)zkw线段树](#3.03)
ex:[线段树优化Dijkstra](#3.03.ex)
4.[树状数组](#3.04)
5.[LCA(最近公共祖先)](#3.05)
(1)[倍增](#3.05.1)
(2)[树链剖分](#3.05.2)
6.[平衡树](#3.06)
(1)[Treap](#3.06.1)
(2)[Splay](#3.06.2)
(3)[FHQ Treap](#3.06.3)
(4)[WBLT](#3.06.4)
7.[权值线段树](#3.07)
8.[主席树(可持久化(权值)线段树)](#3.08)
9.[可持久化数组(可持久化线段树)](#3.09)
10.[二维树状数组](#3.10)
11.[扫描线](#3.11)
12.[可持久化平衡树](#3.12)
13.[树套树](#3.13)
(1)[线段树套FHQ treap](#3.13.1)
14.[分块](#3.14)
15.[左偏树](#3.15)
16.[珂朵莉树(ODT)](#3.16)
四.字符串算法
1.[manacher算法](#4.01.01)
2.[Trie树](#4.01.02)
3.字符串hash
(1)[自然溢出法](#4.01.03.1)
(2)[单模哈希法](#4.01.03.2)
(3)[双模哈希法](#4.01.03.3)
4.[KMP字符串匹配](#4.01.04)
5.[AC自动机](#4.01.05)
五、其他算法
1.排序算法
(1)[归并排序](#5.01.01)
(2)[快速排序](#5.01.02)
(3)[堆排序](#5.01.03)
(4)[冒泡排序](#5.01.04)
2.[LCS(最长公共子序列)](#5.02)
3.[舞蹈链(Dancing_Links_X)](#5.03)
## 一.数论
#### 1.<span id = "1.01">快速幂</span>
```cpp
inline ll mul(ll a,ll b,ll mod){
ll ans = 1;
while(b){
if(b & 1) ans=ans*a%p;
a = a * a % p; b >>= 1;
}
return ans % mod;
}
```
#### 2.<span id = "1.02">欧拉函数</span>
```cpp
inline ll phi(ll n){
ll ans=n;
for(int i = 2; i * i <= n; i++){
if(n % i == 0) ans = ans / i * (i - 1);
while(n % i == 0) n /= i;
}
if(n != 1) ans = ans / n * (n - 1);
return ans;
}
```
#### 3.<span id = "1.03">乘法逆元(线性求逆)</span>
Form 1:
```cpp
ll inv[mn], n, p;
int main(){
n = read(), p = read();
inv[1] = 1;
cout<< 1 <<"\n";
go(i, 2, n, 1){
inv[i] = (-1 * ((p / i) * inv[p % i]) % p + p) % p;
printf("%d\n", inv[i]);
}
return 0;
}
```
Form 2:
**by Rhein_E**
```cpp
LL qpow(LL x, LL y, LL p) {
LL res = 1;
while (y) {
if (y & 1) (res *= x) %= p;
y >>= 1;
(x *= x) %= p;
}
return res;
}
LL inverse1(LL x, LL p) { return qpow(x, p - 2, p); }
void exGCD(LL a, LL b, LL &x, LL &y) {
if (!b) x = 1, y = 0;
else {
exGCD(b, a % b, y, x);
y -= a / b * x;
}
}
LL inverse2(LL x, LL p) {
LL xx, yy;
exGCD(x, p, xx, yy);
xx = (xx % p + p) % p;
return xx;
}
//Rhein_E
```
#### 4.<span id = "1.04">线性筛素数</span>
##### (1)<span id = "1.04.1">埃式筛法</span>
//实质上这个算法不是所谓欧拉的线性筛;而是一个O(nlglgn)的算法,但是在数据很大时,由于这个算法的常数小,且lglgn在数据很大的情况下基本不变,所以在某种意义上这个算法好写且更优秀。
```cpp
bool prime[mn];
int n,m,a;
inline void primee(int nn){
go(i, 0, nn, 1){
prime[i] = true;
}
prime[0] = prime[1] = false;
go(i, 2, nn, 1){
if(!prime[i])
continue;
go(j, 2 * i, nn, i){
prime[j] = false;
}
}
}
int main(){
n=read();m=read();
primee(n);
go(i, 1, m, 1){
a = read();
if(prime[a])
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}
```
##### (2)<span id = "1.04.2">欧拉筛法</span>
```cpp
int v[mn], prime[mn], m;
inline void get_prime(int n) {
m = 0;
go(i, 2, n, 1) {
if(v[i] == 0) {
v[i] = i;
prime[++m] = i;
}
go(j, 1, m, 1) {
if(prime[j] > v[i] || prime[j] > n / i) break;
v[prime[j] * i] = prime[j];
}
}
}
int n, k;
int main() {
n = read(), k = read();
get_prime(n);
go(i, 1, k, 1) {
int x = read();
if(v[x] == x) puts("Yes");
else puts("No");
}
return 0;
}
```
#### 5.<span id = "1.05">扩展欧几里得</span>
Form 1:
```cpp
void ex_gcd(int a, int b, int &x, int &y) {
if(b) ex_gcd(b, a % b, y, x), y -= (a / b) * x;
else x = 1, y = 0;
}
```
Form 2:
**by Rhein_E**
```cpp
void ex_gcd(int a, int b, int &x, int &y, int &d) {
if (!b) d = a, x = 1, y = 0;
else {
ex_gcd(b, a % b, y, x, d);
y -= (a / b) * x;
}
}
```
#### 6.<span id = "1.06">费马小定理</span>
```cpp
inline ll phi(ll n){
ll ans = n;
for(int i = 2; i * i <= n; i++){
if(n % i == 0){
ans = ans / i * (i - 1);
}
while(n % i == 0)
n /= i;
}
if(n != 1){
ans = ans / n * (n - 1);
}
return ans;
}
inline ll mul(ll a,ll b,ll mod){
ll ans = 1;
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod; b >>= 1;
}
return ans % mod;
}
ll a, b;
int main(){
a = read(), b = read();
ll phin = phi(b);
cout << mul(a, phin - 1, b);
return 0;
}
```
#### 7.<span id = "1.07">矩阵加速</span>
```cpp
struct mat {
ll a[4][4];
mat() { go(i, 1, 3, 1) go(j, 1, 3, 1) a[i][j] = 0; }
void init() { go(i, 1, 3, 1) a[i][i] = 1; }
};
inline mat mat_mul(mat a, mat b) {
mat ans;
go(k, 1, 3, 1) go(i, 1, 3, 1) go(j, 1, 3, 1)
ans.a[i][j] += a.a[i][k] * b.a[k][j] % mod, ans.a[i][j] %= mod;
return ans;
}
inline mat mat_pow(mat a, ll b) {
mat ans; ans.init();
for(; b; b >>= 1) {
if(b & 1) ans = mat_mul(ans, a);
a = mat_mul(a, a);
}
return ans;
}
inline void mat_put(mat a) {
go(i, 1, 3, 1) go(j, 1, 3, 1) printf("%lld%c", a.a[i][j], (j == 3) ? '\n' : ' ');
}
```
#### 8.<span id = "1.08">整除分块</span>
##### P2261 \[CQOI2007]余数求和——AC代码
```cpp
ll ans, n, k, sum;
int main(){
n = read(), k = read();
for (ll l = 1, r; l <= n; l = r + 1){
if(k / l != 0)
r = min(k / (k / l), n);
else
r = n;
sum += (k / l) * (r - l + 1) * (l + r) / 2;
}
ans = n * k - sum;
cout << ans;
return 0;
}
```
#### 9.<span id = "1.09">博弈论</span>
##### (1)<span id = "1.09.1">nim游戏</span>
```cpp
int ans, x, n, T;
int main(){
T = read();
while(T--) {
n = read();
ans = 0;
go(i, 1, n, 1) x = read(), ans ^= x; // ()
if(ans) puts("Yes");
else puts("No");
}
return 0;
}
```
#### 10.<span id = "1.10">高斯消元</span>
Form 1:
```cpp
#define eps 1e-9
double A[mn][mn], b[mn], x[mn];
int n;
// 返回0为无解,1为有解,若判断非零解需特判,此处为n * n + 1矩阵
inline int Gauss() {
for(int i = 1; i <= n; i++) {
int r = i;
for(int j = i + 1; j <= n; j++) {
if(fabs(A[r][i]) < fabs(A[j][i]))
r = j;
}
if(fabs(A[r][i]) < eps) return 0;
if(i != r) swap(A[i], A[r]);
double div = A[i][i];
for(int j = i; j <= n + 1; j++) {
A[i][j] /= div;
}
for(int j = i + 1; j <= n; j++) {
div = A[j][i];
for(int k = i; k <= n + 1; k++)
A[j][k] -= A[i][k] * div;
}
}
x[n] = A[n][n + 1];
for(int i = n - 1; i >= 1; i--) {
x[i] = A[i][n + 1];
for(int j = i + 1; j <= n; j++) {
x[i] -= (x[j] * A[i][j]);
}
}
return 1;
}
```
Form 2:
**by Rhein_E**
```cpp
const double eps = 1e-9;
struct Matrix {
double data[105][105];
int r, c;
Matrix(int _r = 0, int _c = 0) : r(_r), c(_c) {}
void eliminate();
void print();
void solve();
} m;
int main() {
scanf("%d", &m.r);
m.c = m.r + 1;
for (int i = 0; i < m.r; ++i)
for (int j = 0; j < m.c; ++j)
std::cin >> m.data[i][j];
m.eliminate();
m.print();
m.solve();
return 0;
}
void Matrix::eliminate() {
for (int i = 0; i < r; ++i) {
if (data[i][i] > -eps && data[i][i] < eps)
for (int j = i + 1; j < r; ++j)
if (data[j][i] > eps || data[j][i] < -eps)
std::swap(data[i], data[j]);
for (int j = i + 1; j < r; ++j)
for (int k = r; k >= i; --k)
if (data[j][i] > eps || data[j][i] < -eps)
data[j][k] = data[j][k] * data[i][i] / data[j][i] - data[i][k];
}
}
void Matrix::print() {
for (int i = 0; i < r; ++i) {
for (int j = 0; j < c; ++j)
printf("%10.5lf ", data[i][j]);
puts("");
}
}
void Matrix::solve() {
for (int i = r - 1; i >= 0; --i) {
data[i][r + 1] = data[i][r];
for (int j = i + 1; j < r; ++j) data[i][r + 1] -= data[j][r + 1] * data[i][j];
data[i][r + 1] /= data[i][i];
}
for (int i = 0; i < r; ++i)
printf("%10.5lf ", data[i][r + 1]);
puts("");
}
//Rhein_E
```
#### 11.<span id = "1.11">Miller-Rabin</span>
```cpp
class Miller_Rabin {
private:
inline ll mul(ll a, ll b, ll mod) {
ll ans = 1ll;
while(b) {
if(b & 1) ans = ans * a % mod;
a = (a * a) % mod, b >>= 1;
}
return ans % mod;
}
inline bool miller_rabin(ll n, ll p) {
ll r = 0, s = n - 1;
if(!(n % p)) return 0;
while(!(s & 1)) ++r, s >>= 1;
ll k = mul(p, s, n);
if(k == 1) return 1;
for(ll j = 0; j < r; ++j, k = k * k % n)
if(k == n - 1) return 1;
return 0;
}
public:
inline bool is_prime(ll x) {
ll p[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
for(int i = 0; i < 13; ++i) {
if(x == p[i]) return 1;
if(!miller_rabin(x, p[i])) return 0;
}
return 1;
}
} mr;
```
#### 12.<span id = "1.12">Pollard-Rho(未卡常版)</span>
```cpp
class Pollard_Rho {
private:
inline ll mul(ll a, ll b, ll mod) {
ll tmp = (a * b - (ll)((long double)a / mod * b + 1.0e-8) * mod);
return tmp < 0 ? tmp + mod : tmp;
}
inline ll pow(ll a, ll b, ll mod) {
ll ans = 1ll; a %= mod;
while(b) {
if(b & 1) ans = mul(a, ans, mod);
a = mul(a, a, mod), b >>= 1;
}
return ans % mod;
}
inline bool miller_rabin(ll n, ll p) {
ll r = 0, s = n - 1;
if(!(n % p)) return 0;
while(!(s & 1)) ++r, s >>= 1;
ll k = pow(p, s, n);
if(k == 1) return 1;
for(ll j = 0; j < r; ++j, k = mul(k, k, n))
if(k == n - 1) return 1;
return 0;
}
ll gcd(ll a, ll b) {
if(b == 0) return a;
return gcd(b, a % b);
}
inline ll pollard_rho(ll n, ll c) {
ll x = rand() % (n - 2) + 1;
ll y = x, i = 1, k = 2;
while(1) {
++i;
x = (mul(x, x, n) + c) % n;
ll d = gcd(y - x, n);
if(1 < d and d < n) return d;
if(y == x) return n;
if(i == k) y = x, k <<= 1;
}
}
public:
std::map<ll, int> mp;
ll max_factor = 0;
inline bool is_prime(ll x) {
if(x == 2 || x == 3) return 1;
if(x % 2 == 0 || x == 1) return 0;
ll p[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
for(int i = 0; i < 25; ++i) {
if(x == p[i]) return 1;
if(!miller_rabin(x, p[i])) return 0;
}
return 1;
}
inline void find_factor(ll n, ll c) {
if(n == 1) return;
if(is_prime(n)) { ++mp[n], max_factor = std::max(max_factor, n); return; }
ll p = n;
while(p >= n)
p = pollard_rho(p, c--);
find_factor(p, c);
find_factor(n / p, c);
}
} pr;
```
#### 13.<span id = "1.13">FFT</span>
##### (1)<span id = 1.13.01>FFT-iterative</span>
**by Rhein_E**
```cpp
// Luogu P3803
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
typedef long long LL;
const double PI = 3.14159265;
#ifdef ONLINE_JUDGE
const int MAXN = 4e6 + 10;
#else
const int MAXN = 100;
#endif
struct Complex {
double real, imag;
Complex(double a = 0, double b = 0) : real(a), imag(b) {}
};
Complex operator+(const Complex &a, const Complex &b) { return Complex(a.real + b.real, a.imag + b.imag); }
Complex operator-(const Complex &a, const Complex &b) { return Complex(a.real - b.real, a.imag - b.imag); }
Complex operator-(const Complex &a) { return Complex(-a.real, -a.imag); }
Complex operator*(const Complex &a, const Complex &b) {
return Complex(a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real);
}
Complex a[MAXN], b[MAXN];
int n, m;
void FFT(Complex *arr, int sz, bool IFFT = 0) {
static int rev[MAXN], bit;
for (bit = 0; (1 << bit) < sz; ++bit)
;
for (int i = 1; i < sz; ++i) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
if (i < rev[i]) std::swap(arr[i], arr[rev[i]]);
}
for (int half = 1; half < sz; half <<= 1) {
Complex wn(cos(PI / half), (IFFT ? -1 : 1) * sin(PI / half));
for (int len = half << 1, st = 0; st < sz; st += len) {
Complex w(1, 0);
for (int i = 0; i < half; ++i, w = w * wn) {
Complex x = arr[st + i], y = w * arr[st + i + half];
arr[st + i] = x + y, arr[st + i + half] = x - y;
}
}
}
if (IFFT) {
for (int i = 0; i < sz; ++i)
arr[i].real = (arr[i].real + 0.5) / sz;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Rhein_E\\Desktop\\code\\cpp\\templates\\in.txt", "r", stdin);
freopen("C:\\Users\\Rhein_E\\Desktop\\code\\cpp\\templates\\out.txt", "w", stdout);
#endif
std::cin >> n >> m;
for (int i = 0; i <= n; ++i)
std::cin >> a[i].real;
for (int i = 0; i <= m; ++i)
std::cin >> b[i].real;
int N = 1, bit = 0;
while (N <= n + m)
N <<= 1;
FFT(a, N);
FFT(b, N);
for (int i = 0; i < N; ++i)
a[i] = a[i] * b[i];
FFT(a, N, 1);
for (int i = 0; i <= n + m; ++i)
std::cout << (int)a[i].real << " ";
std::cout << std::endl;
return 0;
}
// Rhein_E
```
##### (2)<span id = "1.13.02">FFT-recursive</span>
**by Rhein_E**
```cpp
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
typedef long long LL;
const double PI = 3.14159265;
#ifdef ONLINE_JUDGE
const int MAXN = 4e6 + 10;
#else
const int MAXN = 100;
#endif
struct Complex {
double real, imag;
Complex(double a = 0, double b = 0) : real(a), imag(b) {}
};
Complex operator+(const Complex &a, const Complex &b) { return Complex(a.real + b.real, a.imag + b.imag); }
Complex operator-(const Complex &a, const Complex &b) { return Complex(a.real - b.real, a.imag - b.imag); }
Complex operator*(const Complex &a, const Complex &b) {
return Complex(a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real);
}
Complex operator-(const Complex &a) { return Complex(-a.real, -a.imag); }
void FFT(Complex *arr, int n, bool IFFT = 0) {
if (n == 1) return;
Complex *a0 = new Complex[n >> 1], *a1 = new Complex[n >> 1];
for (int i = 0; i < (n >> 1); ++i)
a0[i] = arr[i << 1], a1[i] = arr[i << 1 | 1];
FFT(a0, n >> 1, IFFT), FFT(a1, n >> 1, IFFT);
Complex wn(cos(2 * PI / n), (IFFT ? -1 : 1) * sin(2 * PI / n)), w(1, 0);
for (int i = 0; i < (n >> 1); ++i) {
arr[i] = a0[i] + w * a1[i];
arr[i + (n >> 1)] = a0[i] - w * a1[i];
w = w * wn;
}
}
Complex a[MAXN], b[MAXN];
int n, m;
int main() {
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Rhein_E\\Desktop\\code\\cpp\\templates\\in.txt", "r", stdin);
freopen("C:\\Users\\Rhein_E\\Desktop\\code\\cpp\\templates\\out.txt", "w", stdout);
#endif
std::cin >> n >> m;
for (int i = 0; i <= n; ++i)
std::cin >> a[i].real;
for (int i = 0; i <= m; ++i)
std::cin >> b[i].real;
int N = 1;
while (N <= n + m)
N <<= 1;
FFT(a, N);
FFT(b, N);
for (int i = 0; i < N; ++i)
a[i] = a[i] * b[i];
FFT(a, N, 1);
for (int i = 0; i <= n + m; ++i)
std::cout << (int)(a[i].real / N + 0.5) << " ";
std::cout << std::endl;
return 0;
}
// Rhein_E
```
#### 14.<span id = "1.14">线性异或方程组(在线)</span>
**by Rhein_E**
```cpp
#include <cstdio>
#include <cstring>
#include <iostream>
inline char gc() {
static char buf[1000000], *p1, *p2;
if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
return p1 == p2 ? EOF : *p2++;
}
inline int read() {
int res = 0; char ch = gc(), sg = 0;
while (ch != '-' && (ch < '0' || ch > '9')) ch = gc();
if (ch == '-') ch = gc(), sg = 1;
while (ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + ch - '0', ch = gc();
return sg ? -res : res;
}
const int MAXN = 32;
const int MAXM = 110;
int a[MAXM]; //记录方程
int c[MAXN]; //记录关键元为xi的方程的编号
int main() {
//init
memset(c, -1, sizeof(c));
//input & solve
//读入m个方程的系数及常数项
bool flag = 1;
int n = read(), m = read();
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j)
if (read()) a[i] |= (1 << j);
if (read()) a[i] |= (1 << n);
for (int j = 0; j < n; ++j)
if (a[i] & (1 << j))
if (~c[j]) a[i] ^= a[c[j]]; //关键元被占用,消去当前方程中的xj
else {
c[j] = i; //把当前方程的关键元设为xj
break;
}
if (a[i] == (1 << n)) flag = 0; //消元后得到0=1的形式,无解
}
if (!flag) puts("No Solution.\n");
else {
for (int i = n - 1; i >= 0; --i)
if (~c[i])
for (int j = i - 1; j >= 0; --j)
if ((a[c[j]] >> i) & 1)
a[c[j]] ^= a[c[i]];
for (int i = 0; i < n; ++i)
if (~c[i]) printf("%d ", (a[c[i]] >> n) & 1);
else printf("0 "); //xi可以为1或0,如果为1,需要向上消元
puts("");
}
return 0;
}
```
#### 15.<span id = "1.15">线性递归</span>
**by Rhein_E**
```cpp
//Fibonacci
#include <cstdio>
#include <iostream>
#include <cstring>
typedef long long LL;
const int MAXN = 105;
struct Matrix {
int n;
LL data[MAXN][MAXN];
Matrix(int _n = 0) : n(_n) { memset(data, 0, sizeof(data)); }
Matrix operator*(Matrix a) {
Matrix res(n);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k)
res.data[i][j] += data[i][k] * a.data[k][j];
return res;
}
static Matrix identity(int x) {
Matrix res(x);
for (int i = 0; i < x; ++i) res.data[i][i] = 1;
return res;
}
} base(2), f(2);
int n;
Matrix pow(Matrix x, int y) {
Matrix res = Matrix::identity(x.n);
while (y) {
if (y & 1) res = res * x;
x = x * x;
y >>= 1;
}
return res;
}
int main() {
while (~scanf("%d", &n)) {
base = Matrix(2), f = Matrix(2);
base.data[0][0] = base.data[0][1] = base.data[1][0] = 1;
f.data[0][0] = f.data[1][0] = 1;
f = pow(base, n - 1) * f;
printf("%lld\n", f.data[0][0]);
}
return 0;
}
// Rhein_E
```
#### 16.<span id = "1.16">NTT</span>
##### (1)<span id = "1.16.01">NTT-iterative</span>
**by Rhein_E**
```cpp
// Luogu P3803
#include <cstdio>
#include <cstring>
#include <iostream>
typedef long long LL;
const LL G = 3;
const LL MOD = 998244353;
const int MAXN = 5e6;
LL qpow(LL x, LL y) {
LL res = 1;
while (y) {
if (y & 1) res = (res * x) % MOD;
y >>= 1;
x = (x * x) % MOD;
}
return res;
}
void NTT(LL *arr, int n, bool inv = 0) {
static int rev[MAXN], bit;
for (bit = 0; (1 << bit) < n; ++bit)
;
for (int i = 1; i < n; ++i) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
if (i < rev[i]) std::swap(arr[i], arr[rev[i]]);
}
for (int len = 2; len <= n; len <<= 1) {
LL wn = qpow(G, (MOD - 1) / len);
if (inv) wn = qpow(wn, MOD - 2);
for (int i = 0, half = len >> 1; i < n; i += len) {
LL w = 1;
for (int j = 0; j < half; ++j, w = w * wn % MOD) {
LL x = arr[i + j], y = w * arr[i + j + half] % MOD;
arr[i + j] = (x + y) % MOD, arr[i + j + half] = (x - y + MOD) % MOD;
}
}
}
if (inv) {
LL tmp = qpow(n, MOD - 2);
for (int i = 0; i < n; ++i)
arr[i] = (arr[i] * tmp) % MOD;
}
}
LL a[MAXN], b[MAXN];
int N, M;
int main() {
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Rhein_E\\Desktop\\code\\cpp\\templates\\in.txt", "r", stdin);
freopen("C:\\Users\\Rhein_E\\Desktop\\code\\cpp\\templates\\out.txt", "w", stdout);
#endif
scanf("%d%d", &N, &M);
for (int i = 0; i <= N; ++i)
scanf("%lld", a + i);
for (int i = 0; i <= M; ++i)
scanf("%lld", b + i);
int lim = 1;
while (lim <= M + N)
lim <<= 1;
NTT(a, lim);
NTT(b, lim);
for (int i = 0; i < lim; ++i)
a[i] = a[i] * b[i] % MOD;
NTT(a, lim, 1);
for (int i = 0; i <= N + M; ++i)
printf("%lld ", a[i]);
return 0;
}
// Rhein_E
```
## 二.图论
#### 1.<span id = "2.01">并查集</span>
```cpp
int fa[mn], n, m;
inline int findx(int x) {
if(x == fa[x]) return x;
else return fa[x] = findx(fa[x]);
}
inline void mergex(int x, int y) {
int xx = findx(x), yy = findx(y);
if(xx == yy) return;
if(rand() % 2) fa[xx] = yy;
else fa[yy] = xx;
}
int main() {
n = read(), m = read();
go(i, 1, n, 1) fa[i] = i;
go(i ,1, m, 1) {
int s = read(), x = read(), y = read();
if(s == 1) mergex(x, y);
else {
int xx = findx(x), yy = findx(y);
if(xx == yy) puts("Y");
else puts("N");
}
}
return 0;
}
```
#### 2.<span id = "2.02">Kruskal算法</span>
```cpp
struct edge{
int x, y, w;
} e[mm];
int n, m, b[mn], f[mn], sum = 0, num = 0;
inline int findx(int x) {
return f[x] == x ? x : f[x] = findx(f[x]);
}
inline bool cmp(edge a,edge b) {
return a.w < b.w;
}
inline void Kru() {
go(i, 1, n, 1) {
f[i] = i;
}
sort(e + 1, e + m + 1, cmp);
go(i, 1, m, 1) {
int u = findx(e[i].x);
int v = findx(e[i].y);
if(u != v) {
f[u] = v;
sum += e[i].w;
num++;
if(num == n - 1)
return;
}
}
}
```
#### 3.<span id = "2.03">Dijkstra算法(优化版)</span>
```cpp
struct edge {
int v, nxt, w;
} e[mn << 1];
int h[mn], p;
inline void add(int a, int b, int c) {
e[++p].nxt = h[a], h[a] = p;
e[p].v = b, e[p].w = c;
}
struct node{
int x, d;
bool operator < (const node &b) const { return d > b.d; }
};
priority_queue<node> q;
int n, m, dis[mn];
inline void Dij(int s) {
go(i, 1, n, 1) dis[i] = inf;
node o; o.x = s, o.d = 0;
q.push(o), dis[s] = 0;
while(!q.empty()) {
node o = q.top(); q.pop();
if(o.d != dis[o.x]) continue;
int x = o.x, d = o.d;
rep(i, x) {
int v = e[i].v, w = e[i].w;
if(dis[v] > dis[x] + w) {
dis[v] = dis[x] + w;
node oo; oo.x = v, oo.d = dis[v];
q.push(oo);
}
}
}
}
```
#### 4.<span id = "2.04">SPFA算法</span>
```cpp
struct edge{
int v, nxt, w;
} e[mn << 1];
int h[mn], p;
inline void add(int a,int b,int c){
e[++p].nxt = h[a], h[a] = p, e[p].v = b, e[p].w = c;
}
int dis[mn], vis[mn], n, m, s, t;
inline void SPFA(int s){
go(i, 1, n, 1) dis[i] = inf;
queue<int> q;
q.push(s), dis[s] = 0, vis[s] = 1;
while(!q.empty()){
int x = q.front();
q.pop(); vis[x] = 0;
rep(i, x){
int v = e[i].v, w = e[i].w;
if(dis[v] > dis[x] + w){
dis[v] = dis[x] + w;
if(!vis[v]){
q.push(v), vis[v] = 1;
}
}
}
}
}
```
#### 5.span id = "2.05">Floyd(已优化)<</span>
```cpp
int a[mn][mn], s, m, n, d, b, c;
inline void floyd(){
go(k, 1, n, 1){
go(i, 1, n, 1){
if(i == k || a[i][k] == inf)
continue;
go(j, 1, n, 1){
if(i == j || j == k || a[k][j] == inf)
continue;
if(a[i][k] + a[k][j] < a[i][j]){
a[i][j] = a[i][k] + a[k][j];
}
}
}
}
}
```
#### 6.<span id = "2.06">二分图染色</span>
```cpp
bool vis[mk];
int c[mk];
vector<int> G[mk];
inline bool color(int u){
vis[u] = true;
go(i, 0, G[u].size() - 1, 1){
int v = G[u][i];
if(vis[v]){
if(c[v] != c[u])
return false;
} else {
c[v] = !c[u];
if(!color(v))
return false;
}
}
return true;
}
```
#### 7.<span id = "2.07">拓扑排序</span>
```cpp
struct edge{ int v, nxt; } e[mm << 1]; int h[mn], p;
inline void add(int a, int b) { e[++p].nxt = h[a], h[a] = p, e[p].v = b; }
int n, m, du[mn];
vector<int> sorted;
queue<int> q;
inline void topsort() {
go(i, 1, n, 1) if(!du[i]) q.push(i);
while(!q.empty()) {
int x = q.front(); q.pop();
sorted.push_back(x);
rep(i, x) {
int v = e[i].v;
if(!--du[v]) q.push(v);
}
}
}
int main() {
n = read(), m = read();
go(i, 1, m, 1) {
int a = read(), b = read();
add(a, b); du[b]++;
}
topsort();
int sze = sorted.size();
go(i, 0, sze - 1, 1)
printf("%d ", sorted[i]);
return 0;
}
```
#### 8.<span id = "2.08">缩点(tarjan求强联通分量)</span>
```cpp
struct edge{ int v, nxt; } e[mn << 1], ee[mn << 1]; int h[mn], p, hh[mn], pp;
inline void add(int a, int b) { e[++p].nxt = h[a], h[a] = p, e[p].v = b; }
inline void aadd(int a, int b) { ee[++pp].nxt = hh[a], hh[a] = pp, ee[pp].v = b; }
int dfn[mn], low[mn], co[mn], st[mn], top, cnt, ans, col, n, m, w[mn], b[mn], du[mn], dp[mn];
void tarjan(int x) {
dfn[x] = low[x] = ++cnt;
st[++top] = x;
rep(i, x) {
int v = e[i].v;
if(!dfn[v]) {
tarjan(v);
low[x] = min(low[x], low[v]);
} else if(!co[v]) {
low[x] = min(low[x], dfn[v]);
}
}
if(dfn[x] == low[x]) {
++col;
while(st[top + 1] != x) {
co[st[top]] = col;
b[col] += w[st[top]];
top--;
}
}
}
void dfs(int x, int f) {
if(dp[x]) return;
dp[x] = b[x];
int maxx = 0;
for(int i = hh[x]; i; i = ee[i].nxt) {
int v = ee[i].v;
if(v == f) continue;
dfs(v, x);
maxx = max(maxx, dp[v]);
}
dp[x] += maxx;
}
inline void debug() {
go(i, 1, col, 1) printf("%d%c", b[i], (i == col) ? '\n' : ' ');
}
int main() {
n = read(), m = read();
go(i, 1, n, 1) w[i] = read();
go(i, 1, m, 1) {
int a = read(), b = read();
add(a, b);
}
go(i, 1, n, 1) if(!dfn[i]) tarjan(i);
go(x, 1, n, 1) {
rep(i, x) {
int v = e[i].v;
if(co[x] != co[v])
aadd(co[x], co[v]), du[co[v]]++;
}
}
// debug();
go(i, 1, col, 1) {
if(!dp[i]) dfs(i, 0), ans = max(ans, dp[i]);
}
cout << ans << "\n";
return 0;
}
```
#### 9.<span id = "2.09">割点(割顶)</span>
```cpp
inline void tarjan(int x, int rt) { // rt 是根节点QwQ
int rtc = 0;
dfn[x] = low[x] = ++cnt;
rep(i, x) {
int v = e[i].v;
if(!dfn[v]) {
tarjan(v, rt);
low[x] = std::min(low[x], low[v]);
if(low[v] >= dfn[x] && x != rt) cut[x] = 1;
if(x == rt) rtc++;
}
low[x] = std::min(low[x], dfn[v]);
}
if(x == rt && rtc >= 2) cut[rt] = 1;
}
inline void solve() {
n = read(), m = read();
go(i, 1, m, 1) {
int a = read(), b = read();
add(a, b), add(b, a);
}
go(i, 1, n, 1) if(!dfn[i]) tarjan(i, i);
go(i, 1, n, 1) ans += cut[i];
std::printf("%d\n", ans);
go(i, 1, n, 1) if(cut[i]) printf("%d\n", i);
}
inline void init() {
memset(h, -1, sizeof h);
p = -1;
}
```
#### 10.<span id = "2.10">树分治</span>
##### (1)<span id = "2.10.1">点分治(包括求树的重心)</span>
```cpp
struct edge { int v, nxt, w; } e[mn << 1]; int h[mn], p = -1;
inline void add(int a, int b, int c) { e[++p].nxt = h[a], h[a] = p, e[p].v = b, e[p].w = c; }
int maxp[mn], sze[mn], dis[mn], rem[mn], vis[mn], test[mn], judge[mn], q[mn * 100], query[mn];
int n, m, sum, rot, ans;
void get_root(int x, int f) {
sze[x] = 1, maxp[x] = 0;
rep(i, x) {
int v = e[i].v;
if(v == f || vis[v]) continue;
get_root(v, x);
sze[x] += sze[v];
maxp[x] = max(maxp[x], sze[v]);
}
maxp[x] = max(maxp[x], sum - sze[x]);
if(maxp[x] < maxp[rot]) rot = x;
}
void get_dis(int x, int f) {
rem[++rem[0]] = dis[x];
rep(i, x) {
int v = e[i].v, w = e[i].w;
if(v == f || vis[v]) continue;
dis[v] = dis[x] + w;
get_dis(v, x);
}
}
inline void calc(int x) {
int p = 0;
rep(i, x) {
int v = e[i].v, w = e[i].w;
if(vis[v]) continue;
rem[0] = 0, dis[v] = w;
get_dis(v, x);
fo(j, rem[0], 1, 1)
go(k, 1, m, 1)
if(query[k] >= rem[j])
test[k] |= judge[query[k] - rem[j]];
fo(j, rem[0], 1, 1)
q[++p] = rem[j], judge[rem[j]] = 1;
}
go(i, 1, p, 1)
judge[q[i]] = 0;
}
void pit_div(int x) { // point divide
vis[x] = judge[0] = 1;
calc(x);
rep(i, x) {
int v = e[i].v;
if(vis[v]) continue;
sum = sze[v], maxp[rot = 0] = inf;
get_root(v, 0);
pit_div(v);
}
}
inline void solve() {
n = read(), m = read();
go(i, 1, n - 1, 1) {
int x = read(), y = read(), z = read();
add(x, y, z), add(y, x, z);
}
go(i, 1, m, 1) query[i] = read();
maxp[rot] = sum = n;
get_root(1, -1);
pit_div(rot);
go(i, 1, m, 1)
if(test[i]) puts("AYE");
else puts("NAY");
}
inline void init() {
memset(h, -1, sizeof h);
p = -1;
}
int main() {
init();
solve();
return 0;
}
```
### 11.网络流
#### (一)网络最大流
#### (1)<span id = "2.11.01.1">EK算法</span>
##### P3376 【模板】网络最大流——AC代码
P.S.注释的部分为邻接矩阵的操作
```cpp
bool vis[mn];
int n, m;
struct edge { int v, nxt, w; } e[mn << 1]; int h[mn], p = -1;
inline void add(int a, int b, int c) { e[++p].nxt = h[a], h[a] = p, e[p].v = b, e[p].w = c; }
struct node { int v, id; } pre[mn];
inline bool bfs(int s,int t) {
memset(pre, -1, sizeof pre);
memset(vis, 0, sizeof vis);
vis[s] = true;
queue<int> q;
q.push(s);
while(!q.empty()) {
int x = q.front();
q.pop();
// go(i, 1, n, 1)
// if(!vis[i] && g[x][i] > 0) {
// vis[i] = true;
// pre[i] = x;
// if(i == t) return true;
// q.push(i);
// }
rep(i, x) {
int v = e[i].v, w = e[i].w;
if(!vis[v] && w > 0) {
vis[v] = true;
pre[v].v = x;
pre[v].id = i;
if(v == t) return true;
q.push(v);
}
}
}
return false;
}
inline int EK(int s, int t) {
int d, maxflow;
maxflow = 0;
while(bfs(s, t)) {
d = inf;
for(int i = t; i != s; i = pre[i].v)
d = min(d, e[pre[i].id].w);
for(int i = t; i != s; i = pre[i].v) {
e[pre[i].id].w -= d;
e[pre[i].id ^ 1].w += d;
}
maxflow += d;
}
return maxflow;
}
inline void solve() {
n = read(), m = read();
int s = read(), t = read();
go(i, 1, m, 1) {
int x = read(), v = read(), w = read();
// g[x][v] += w;
add(x, v, w);
add(v, x, 0);
}
cout << EK(s, t) << "\n";
}
inline void init() {
memset(h, -1, sizeof h);
}
int main() {
init();
solve();
return 0;
}
```
##### (2)<span id = "2.11.01.2">Dinic算法</span>
##### P3376 【模板】网络最大流——AC代码
```cpp
int n, m;
struct edge {
int v, nxt, w;
} e[mn << 1];
int h[mn], p = -1;
inline void add(int a, int b, int c) {
e[++p].nxt = h[a], h[a] = p, e[p].v = b, e[p].w = c;
}
inline void add_flow(int a, int b, int c) { add(a, b, c), add(b, a, 0); }
int dep[mn], cur[mn];
inline bool bfs(int s, int t) {
go(i, 1, n, 1) dep[i] = inf, cur[i] = h[i];
queue<int> q; dep[s] = 0, q.push(s);
while(!q.empty()) {
int x = q.front(); q.pop();
rep(i, x) {
int v = e[i].v, w = e[i].w;
if(dep[v] >= inf && w) {
dep[v] = dep[x] + 1;
q.push(v);
}
}
}
if(dep[t] < inf) return true;
return false;
}
inline int dfs(int x, int t, int lim) {
if(x == t || !lim) return lim;
int flow = 0, f = 0;
curep(i, x) {
int v = e[i].v, w = e[i].w;
cur[x] = i;
if(dep[v] == dep[x] + 1 && (f = dfs(v, t, min(lim, w)))) {
flow += f, lim -= f;
e[i].w -= f, e[i ^ 1].w += f;
if(!lim) break;
}
}
return flow;
}
inline int Dinic(int s, int t) {
int maxflow = 0;
while(bfs(s, t)) maxflow += dfs(s, t, inf);
return maxflow;
}
inline void solve() {
n = read(), m = read();
int s = read(), t = read(), x, y, z;
go(i, 1, m, 1) x = read(), y = read(), z = read(), add_flow(x, y, z);
cout << Dinic(s, t) << "\n";
}
inline void init() {
memset(h, -1, sizeof h);
p = -1;
}
int main () {
init();
solve();
return 0;
}
```
##### (3)<span id = "2.11.01.3">预流推进HLPP</span>
```cpp
int n, m, dep[mn];
struct cmp {
inline bool operator() (int a, int b) const { return dep[a] < dep[b]; }
};
class Preflow_propulsion {
private:
struct edge {
int v, nxt; ll w;
} e[mm << 1];
int h[mn], p = -1;
inline void add(int a, int b, ll c) {
e[++p].nxt = h[a], h[a] = p, e[p].v = b, e[p].w = c;
}
// int G[mn][mn];
ll flow[mn];
// int dep[mn];
int gap[mn << 1];
int vis[mn];
const int infx = 0x3f3f3f3f;
inline bool bfs(int s, int t) {
std::memset(dep, 0x3f, sizeof dep);
std::queue<int> qq;
qq.push(t), dep[t] = 0;
while(!qq.empty()) {
int x = qq.front(); qq.pop();
rep(i, x) {
int v = e[i].v;
if(dep[v] > dep[x] + 1 && e[i ^ 1].w)
qq.push(v), dep[v] = dep[x] + 1;
}
}
return dep[s] != infx;
}
std::priority_queue<int, std::vector<int>, cmp> q;
inline void push(int x, int s, int t) {
rep(i, x) {
int v = e[i].v; ll w = e[i].w;
if(w && dep[v] + 1 == dep[x]) {
ll fl = std::min(flow[x], e[i].w);
e[i].w -= fl, e[i ^ 1].w += fl;
flow[x] -= fl, flow[v] += fl;
if(v != s and v != t and !vis[v])
q.push(v), vis[v] = 1;
if(!flow[x]) break;
}
}
}
inline void relabel(int x) {
dep[x] = infx;
rep(i, x) {
int v = e[i].v; ll w = e[i].w;
if(w && dep[x] > dep[v] + 1)
dep[x] = dep[v] + 1;
}
}
inline ll hlpp(int s, int t) {
if(!bfs(s, t)) return 0;
dep[s] = n;
std::memset(gap, 0, sizeof gap);
go(i, 1, n, 1) if(dep[i] < infx) ++gap[dep[i]];
rep(i, s) {
int v = e[i].v; ll w = e[i].w;
if(w) {
e[i].w -= w, e[i ^ 1].w += w;
flow[s] -= w, flow[v] += w;
if(!vis[v] and v != s and v != t)
q.push(v), vis[v] = 1;
}
}
while(!q.empty()) {
int x = q.top(); q.pop(), vis[x] = 0;
push(x, s, t);
if(flow[x]) {
if(!--gap[dep[x]])
go(i, 1, n, 1)
if(i != s && i != t && dep[i] > dep[x] && dep[i] < n + 1)
dep[i] = n + 1;
relabel(x);
++gap[dep[x]];
q.push(x), vis[x] = 1;
}
}
return flow[t];
}
public:
inline void init() {
std::memset(h, -1, sizeof h);
p = -1;
}
inline void get_maxf(int s, int t, ll &maxflow) { maxflow = hlpp(s, t); }
inline void add_flow(int a, int b, int c) { add(a, b, c), add(b, a, 0); }
} hlpp;
```
#### 2.最小费用最大流
##### (1)<span id = "2.11.02.1">SPFA版</span>
##### P3381 【模板】最小费用最大流——AC代码
注释部分为EK的代码(对比修改
```cpp
int n, m;
struct edge{
int v, nxt, w, d;
} e[mn << 1];
int h[mn], p = -1;
inline void add(int a, int b, int c, int d) {
e[++p].nxt = h[a], h[a] = p, e[p].v = b, e[p].w = c, e[p].d = d;
}
inline void add_flow(int a, int b, int c, int d) { add(a, b, c, d), add(b, a, 0, -d); }
struct node {
int v, id;
} pre[mn];
bool vis[mn];
inline bool bfs(int s, int t) {
memset(pre, -1, sizeof pre);
memset(vis, 0, sizeof vis);
vis[s] = 1;
queue<int> q; q.push(s);
while(!q.empty()) {
int x = q.front(); q.pop();
rep(i, x) {
int v = e[i].v, w = e[i].w;
if(!vis[v] && w){
vis[v] = 1;
pre[v].v = x, pre[v].id = i;
if(v == t) return true;
q.push(v);
}
}
}
return false;
}
int dis[mn], flow[mn];
inline bool SPFA(int s, int t) {
memset(dis, 0x7f, sizeof dis);
memset(flow, 0x7f, sizeof flow);
memset(vis, 0, sizeof vis);
memset(pre, -1, sizeof pre);
queue<int> q; q.push(s);
dis[s] = 0, vis[s] = 1;
while(!q.empty()) {
int x = q.front(); q.pop();
vis[x] = 0;
rep(i, x) {
int v = e[i].v, w = e[i].w, d = e[i].d;
if(w && dis[v] > dis[x] + d) {
dis[v] = dis[x] + d;
pre[v].v = x;
pre[v].id = i;
flow[v] = min(flow[x], w);
if(!vis[v]) q.push(v), vis[v] = 1;
}
}
}
if(pre[t].v != -1) return true;
return false;
}
inline int EK(int s, int t) {
int d, maxflow = 0;
while(bfs(s, t)) {
d = inf;
for(int i = t; i != s; i = pre[i].v)
d = min(d, e[pre[i].id].w);
for(int i = t; i != s; i = pre[i].v)
e[pre[i].id].w -= d,
e[pre[i].id ^ 1].w += d;
maxflow += d;
}
return maxflow;
}
int maxflow, mincost;
inline void MCMF(int s, int t) {
while(SPFA(s, t)) {
maxflow += flow[t];
mincost += flow[t] * dis[t];
for(int i = t; i != s; i = pre[i].v) {
e[pre[i].id].w -= flow[t];
e[pre[i].id ^ 1].w += flow[t];
}
}
}
inline void solve() {
n = read(), m = read();
int s = read(), t = read(), x, y, z, w;
go(i, 1, m, 1)
x = read(), y = read(), z = read(), w = read(),
add_flow(x, y, z, w);
// cout << EK(s, t);
MCMF(s, t);
cout << maxflow << " " << mincost << "\n";
}
inline void init() {
memset(h, -1, sizeof h);
p = -1;
}
int main () {
init();
solve();
return 0;
}
```
##### (2)<span id = "2.11.02.2">Dijkstra版</span>
**by Rhein_E**
```cpp
// Luogu P1251
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
typedef long long LL;
typedef std::pair<LL, int> pli;
const int MAXN = 2010, MAXM = MAXN * 7;
const LL INF = 0x3f3f3f3f3f3f3f3fll;
struct Graph {
struct Edge {
int v, cap, cost, next;
Edge(int _v = 0, int _c = 0, int _co = 0, int _n = 0) : v(_v), cap(_c), cost(_co), next(_n) {}
} E[MAXM << 1];
int n, head[MAXN << 1], cnt, pre[MAXN << 1];
LL h[MAXN << 1], dis[MAXN << 1];
int s, t;
void init(int _s, int _t, int _n) {
s = _s, t = _t, n = _n, cnt = 0;
memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int cap, int cost) {
E[cnt] = Edge(v, cap, cost, head[u]);
head[u] = cnt++;
E[cnt] = Edge(u, 0, -cost, head[v]);
head[v] = cnt++;
}
bool Dijkstra() {
static std::priority_queue<pli, std::vector<pli>, std::greater<pli>> q;
static bool vis[MAXN << 1];
memset(vis, 0, sizeof(vis));
memset(dis, 0x3f, sizeof(dis));
memset(pre, -1, sizeof(pre));
dis[s] = 0;
q.push(std::make_pair(0ll, s));
while (!q.empty()) {
int u = q.top().second;
q.pop();
if (vis[u])
continue;
vis[u] = 1;
for (int i = head[u]; ~i; i = E[i].next)
if (E[i].cap && dis[E[i].v] > dis[u] + E[i].cost + h[u] - h[E[i].v]) {
dis[E[i].v] = dis[u] + E[i].cost + h[u] - h[E[i].v];
pre[E[i].v] = i;
q.push(std::make_pair(dis[E[i].v], E[i].v));
}
}
return (dis[t] ^ INF);
}
LL MCMF() {
LL res = 0;
while (Dijkstra()) {
int max_flow = (int)INF;
for (int i = 0; i < n; ++i)
h[i] += dis[i];
for (int p = pre[t]; ~p; p = pre[E[p ^ 1].v])
max_flow = std::min(max_flow, E[p].cap);
res += max_flow * h[t];
for (int p = pre[t]; ~p; p = pre[E[p ^ 1].v])
E[p].cap -= max_flow, E[p ^ 1].cap += max_flow;
}
return res;
}
} G;
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int N, n, m, s, f, p;
std::cin >> N;
G.init(0, N << 1 | 1, (N << 1) + 2);
for (int i = 1; i <= N; ++i) {
int t;
std::cin >> t;
G.addEdge(0, i, t, 0);
G.addEdge(i + N, N << 1 | 1, t, 0);
}
std::cin >> p >> m >> f >> n >> s;
for (int i = 1; i <= N; ++i)
G.addEdge(0, i + N, INF, p);
for (int i = 1; i + m <= N; ++i)
G.addEdge(i, i + m + N, INF, f);
for (int i = 1; i + n <= N; ++i)
G.addEdge(i, i + n + N, INF, s);
for (int i = 1; i < N; ++i)
G.addEdge(i, i + 1, INF, 0);
std::cout << G.MCMF() << std::endl;
return 0;
}
// Rhein_E
```
#### 12.<span id = "2.12">树链剖分</span>
##### P3384 【模板】树链剖分——AC代码
```cpp
int mod;
int n, m, r;
int b[mn];
struct segmenttree{
int z[mn << 2], col[mn << 2];
inline void update(int rt){
z[rt] = (z[rt << 1] + z[rt << 1 | 1]) % mod;
}
inline int operation(int a,int b){
return (a + b) % mod;
}
inline void color(int l,int r,int rt,int v){
z[rt] += (r - l + 1) * v;
col[rt] += v;
}
inline void push_col(int l,int r,int rt){
if(col[rt]){
int m = (l + r) >> 1;
color(lson, col[rt]);
color(rson, col[rt]);
col[rt] = 0;
}
}
inline void build(int l,int r,int rt){
if(l==r){
z[rt] = b[l] % mod;
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
update(rt);
}
inline void modify(int l,int r,int rt,int nowl,int nowr,int v){
if(nowl<=l && r<=nowr){
color(bson, v);
return;
}
int m = (l + r) >> 1;
push_col(bson);
if(nowl<=m)
modify(lson, nowl, nowr, v);
if(m<nowr)
modify(rson, nowl, nowr, v);
update(rt);
}
inline int query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr){
return z[rt] % mod;
}
int m = (l + r) >> 1;
push_col(bson);
if(nowl<=m){
if(m<nowr)
return operation(query(lson, nowl, nowr), query(rson, nowl, nowr));
else
return query(lson, nowl, nowr);
}else{
return query(rson, nowl, nowr);
}
}
} tr;
//Line Segment Tree ----------------------------------------
struct edge{
int v,nxt;
} e[mn<<1];
int h[mn],p;
int w[mn];
inline void add(int a,int b){
p++;
e[p].nxt=h[a];
h[a]=p;
e[p].v=b;
}
//adjacency list ------------------------------------------
int dep[mn], fa[mn], son[mn], id[mn], sze[mn], top[mn];
int cnt;
//arrs ----------------------------------------------------
void dfs1(int x,int f,int deep){
dep[x] = deep;
fa[x] = f;
sze[x] = 1;
int maxson = -1;
rep(i,x){
int v = e[i].v;
if(v==f)
continue;
dfs1(v, x, deep + 1);
sze[x] += sze[v];
if(sze[v] > maxson)
maxson = sze[v], son[x] = v;
}
}
void dfs2(int x,int topf){
id[x] = ++cnt;
b[id[x]] = w[x];
top[x] = topf;
if(!son[x])
return;
dfs2(son[x], topf);
rep(i,x){
int v = e[i].v;
if (v == son[x] || v == fa[x])
continue;
dfs2(v, v);
}
}
//DFS -----------------------------------------------------
inline int query1(int x,int y){
int ans = 0;
while(top[x] != top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x, y);
ans += tr.query(root, id[top[x]], id[x]);
ans %= mod;
x = fa[top[x]];
}
if(dep[x]>dep[y])
swap(x, y);
ans += tr.query(root, id[x], id[y]);
ans %= mod;
return ans;
}
inline void modify1(int x,int y,int v){
v %= mod;
while(top[x] != top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x, y);
tr.modify(root, id[top[x]], id[x], v);
x = fa[top[x]];
}
if(dep[x]>dep[y])
swap(x, y);
tr.modify(root, id[x], id[y], v);
}
inline int query2(int x){
return tr.query(root, id[x], id[x] + sze[x] - 1);
}
inline void modify2(int x,int v){
v %= mod;
tr.modify(root, id[x], id[x] + sze[x] - 1, v);
}
//Change and Query ----------------------------------------
int main(){
n = read(), m = read(), r = read(), mod = read();
go(i,1,n,1){
w[i] = read();
}
go(i,1,n-1,1){
int x = read(), y = read();
add(x, y), add(y, x);
}
dfs1(r, 0, 1);
dfs2(r, r);
tr.build(root);
go(i,1,m,1){
int s = read();
if(s==1){
int x = read(), y = read(), z = read();
modify1(x, y, z);
}else if(s==2){
int x = read(), y = read();
cout << query1(x, y) << "\n";
}else if(s==3){
int x = read(), z = read();
modify2(x, z);
}else if(s==4){
int x = read();
cout << query2(x) << "\n";
}
}
return 0;
}
```
#### 13.<span id = "2.13">Prim</span>
**by Rhein_E**
```cpp
//Luogu P3366
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
typedef long long LL;
typedef std::pair<int, int> pii;
const int MAXN = 5005;
const int MAXM = 400005;
struct Graph {
struct Edge {
int v, next, len;
} edge[MAXM];
int n, m, cnt, head[MAXN];
void init(int, int);
void buildEdge(int, int, int);
int Prim(int start = 1);
} G;
int main() {
int N, M;
while (~scanf("%d%d", &N, &M)) {
G.init(N, M);
while (M--) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
G.buildEdge(a, b, c);
G.buildEdge(b, a, c);
}
int ans = G.Prim();
if (~ans) printf("%d\n", ans);
else puts("orz");
}
return 0;
}
void Graph::init(int _n = 0, int _m = 0) {
cnt = 0;
memset(head, -1, sizeof(head));
}
void Graph::buildEdge(int x, int y, int d) {
edge[cnt].v = y, edge[cnt].len = d;
edge[cnt].next = head[x];
head[x] = cnt++;
}
int Graph::Prim(int start) {
int res = 0;
static std::priority_queue<pii, std::vector<pii>, std::greater<pii> > q;
static bool vis[MAXN];
vis[start] = 1;
for (int i = head[start]; ~i; i = edge[i].next)
q.push(std::make_pair(edge[i].len, edge[i].v));
while (!q.empty()) {
pii p = q.top();
q.pop();
if (vis[p.second]) continue;
vis[p.second] = 1;
res += p.first;
for (int i = head[p.second]; ~i; i = edge[i].next)
if (!vis[edge[i].v]) q.push(std::make_pair(edge[i].len, edge[i].v));
}
for (int i = 1; i <= n; ++i) if (!vis[i]) return -1;
return res;
}
```
## 三.数据结构
#### 1.<span id = "3.01">堆</span>
```cpp
inline void swap(int &a, int &b) {
int t = a; a = b; b = t;
}
int size, n, heap[mn];
inline void puth(int x) {
int now, next;
heap[++size] = x;
now = size;
while (now > 1) {
next = now >> 1;
if (heap[now] >= heap[next]) return;
swap(heap[now], heap[next]);
now = next;
}
}
inline void geth() {
cout << heap[1] << "\n";
return;
}
inline int delh()
{
int now, next, res;
res = heap[1];
heap[1] = heap[size--];
now = 1;
while (now * 2 <= size) {
next = now * 2;
if (next < size && heap[next + 1] < heap[next]) next++;
if (heap[now] <= heap[next]) return res;
swap(heap[now], heap[next]);
now = next;
}
}
```
#### 2.<span id = "3.02">线段树</span>
```cpp
ll z[mn << 2], col[mn << 2];
inline void update(int rt) {
z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
inline void color(int l, int r, int rt, ll v) {
col[rt] += v;
z[rt] += (r - l + 1) * v;
}
inline void push_col(int l, int r, int rt) {
if(col[rt]) {
int m = (l + r) >> 1;
color(lson, col[rt]);
color(rson, col[rt]);
col[rt] = 0;
}
}
inline void build(int l, int r, int rt) {
if(l == r) { z[rt] = read(); return; }
int m = (l + r) >> 1;
build(lson), build(rson);
update(rt);
}
inline void modify(int l, int r, int rt, int nowl, int nowr, ll v) {
if(nowl <= l && r <= nowr) { color(bson, v); return; }
int m = (l + r) >> 1;
push_col(bson);
if(nowl <= m) modify(lson, nowl, nowr, v);
if(m < nowr) modify(rson, nowl, nowr, v);
update(rt);
}
inline ll query(int l, int r, int rt, int nowl, int nowr) {
if(nowl <= l && r <= nowr) return z[rt];
int m = (l + r) >> 1;
push_col(bson);
if(nowl <= m)
if(m < nowr)
return query(lson, nowl, nowr) + query(rson, nowl, nowr);
else return query(lson, nowl, nowr);
else return query(rson, nowl, nowr);
}
```
##### 万能模板(结构体)
```cpp
struct tree{
ll x;
};
struct SegmentTree{
tree z[mn << 2];
ll col[mn << 2];
inline void update(int rt){
z[rt].x = z[rt << 1].x + z[rt << 1 | 1].x;
}
inline tree operation(tree a,tree b){
return (tree){a.x + b.x};
}
inline void color(int l,int r,int rt,ll v){
z[rt].x += (r - l + 1) * v;
col[rt] += v;
}
inline void push_col(int l,int r,int rt){
if(col[rt]){
int m = (l + r) >> 1;
color(lson, col[rt]);color(rson, col[rt]);
col[rt] = 0;
}
}
inline void build(int l,int r,int rt){
if(l==r){z[rt].x = read();return;}
int m = (l + r) >> 1;build(lson);build(rson); update(rt);
}
inline void modify(int l,int r,int rt,int nowl,int nowr,ll v){
if(nowl<=l && r<=nowr){color(bson, v); return;}
int m = (l + r) >> 1; push_col(bson);
if(nowl<=m) modify(lson, nowl, nowr, v);
if(m<nowr) modify(rson, nowl, nowr, v);
update(rt);
}
inline tree query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr) return z[rt];
int m = (l + r) >> 1; push_col(bson);
if(nowl<=m){
if(m<nowr) return operation(query(lson, nowl, nowr), query(rson, nowl, nowr));
else return query(lson, nowl, nowr);
}else return query(rson, nowl, nowr);
}
} tr;
```
#### 3.<span id = "3.03">(ex_线段树)zkw线段树</span>
learn from dalao : GKxx
```cpp
ll z[mn << 2];
int n, m, M;
inline void update(int rt) {
z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
inline void build() {
for (M = 1; M < n; M <<= 1) ;
for (int i = M + 1; i <= M + n; i++) z[i] = read();
for (int i = M - 1; i; i--) update(i);
}
inline ll query(int l, int r) {
ll ans = 0;
for (--l += M, ++r += M; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1) ans += z[l ^ 1];
if (r & 1) ans += z[r ^ 1];
}
return ans;
}
inline void modify(int rt, ll v) {
for (z[rt += M] += v, rt >>= 1; rt; rt >>= 1) update(rt);
}
```
#### <span id = "3.03.ex">ex:线段树优化Dijkstra</span>
learn from dalao: Gkxx
```cpp
int minn[mn << 2], pos[mn << 2], M, n, m;
inline void update(int rt) {
minn[rt] = min(minn[rt << 1], minn[rt << 1 | 1]);
pos[rt] = (minn[rt << 1] < minn[rt << 1 | 1]) ? pos[rt << 1] : pos[rt << 1 | 1];
}
inline void build() {
for(M = 1; M < n + 2; M <<= 1) ;
go(i, M, (M << 1) - 1, 1) minn[i] = inf, pos[i] = i - M;
fo(i, M, 1, 1) update(i);
}
inline void modify(int rt, int v) {
for(minn[rt += M] = v, rt >>= 1; rt; rt >>= 1) update(rt);
}
struct edge{ int v, nxt, w; } e[mm << 1]; int h[mn], p;
inline void add(int a, int b, int c) { e[++p].nxt = h[a], h[a] = p, e[p].v = b, e[p].w = c; }
int dis[mn];
inline void Dij(int s) {
go(i, 1, n, 1) dis[i] = inf;
dis[s] = 0, build(), modify(s, 0);
while(minn[1] < inf) {
int x = pos[1], d = minn[1]; modify(x, inf);
if(d != dis[x]) continue;
rep(i, x) {
int v = e[i].v, w = e[i].w;
if(dis[v] > dis[x] + w)
dis[v] = dis[x] + w, modify(v, dis[v]);
}
}
}
```
#### 4.<span id = "3.04">树状数组</span>
```cpp
ll y[mn];
int n, m;
inline ll lb(int x) { return x & -x; }
inline void modify(int p, ll v) {
for (; p <= n; p += lb(p)) y[p] += v;
}
inline ll query(int p) {
int ans = 0;
for (; p; p -= lb(p)) ans += y[p];
return ans;
}
```
#### 5.<span id = "3.05">LCA(最近公共祖先)</span>
##### (1)<span id = "3.05.1">倍增版</span>
```cpp
struct edge {
int v, nxt;
} e[mn << 1];
int h[mn], p;
inline void add(int a, int b) {
e[++p].nxt = h[a], h[a] = p, e[p].v = b;
}
int dep[mn], fa[mn][mk], n, m, s;
void dfs(int x, int f) {
// printf(" -- %d -- \n", x);
dep[x] = dep[f] + 1;
fa[x][0] = f;
for(int i = 1; (1 << i) <= dep[x]; ++i)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
rep(i, x) {
int v = e[i].v;
if(v == f) continue;
dfs(v, x);
}
}
inline int LCA(int a, int b) {
if(dep[a] > dep[b]) swap(a, b);
fo(i, mk - 1, 0, 1)
if(dep[a] <= dep[b] - (1 << i))
b = fa[b][i];
if(a == b) return a;
fo(i, mk - 1, 0, 1) {
if(fa[a][i] == fa[b][i]) continue;
else a = fa[a][i], b = fa[b][i];
}
return fa[a][0];
}
```
##### (2)<span id = "3.05.2">树链剖分版</span>
```cpp
struct edge{
int v, nxt;
}e[mn << 1];
int h[mn], p;
inline void add(int a, int b) {
e[++p].nxt = h[a], h[a] = p, e[p].v = b;
}
int dep[mn], top[mn], sze[mn], fa[mn], son[mn], n, m;
void dfs1(int x, int f, int deep) {
dep[x] = deep;
sze[x] = 1;
fa[x] = f;
int maxson = -1;
rep(i, x) {
int v = e[i].v;
if(v == f) continue;
dfs1(v, x, deep + 1);
sze[x] += sze[v];
if(maxson < sze[v]) maxson = sze[v], son[x] = v;
}
}
void dfs2(int x, int topf) {
top[x] = topf;
if(!son[x]) return;
dfs2(son[x], topf);
rep(i, x) {
int v = e[i].v;
if(v == fa[x] || v == son[x]) continue;
dfs2(v, v);
}
}
inline int LCA(int x, int y) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
int main() {
n = read(), m = read();
int rot = read();
go(i, 1, n - 1, 1) {
int a = read(), b = read();
add(a, b), add(b, a);
}
dfs1(rot, 0, 1);
dfs2(rot, rot);
go(i, 1, m, 1) {
int x = read(), y = read();
printf("%d\n", LCA(x, y));
}
return 0;
}
```
#### 6.<span id = "3.06">平衡树</span>
#### (1)<span id = "3.06.1">Treap</span>
```cpp
int rt, tot;
struct tree{
int size, ch[2], w, pos;
};
struct Treap{
tree z[mn];
inline void update(int rt){
z[rt].size = z[z[rt].ch[0]].size + z[z[rt].ch[1]].size + 1;
}
inline void rotate(int &rt,int p){
int t = z[rt].ch[p];
z[rt].ch[p] = z[t].ch[p ^ 1], z[t].ch[p ^ 1] = rt;
update(rt), update(t);
rt = t;
}
inline void add(int x,int &rt){
if(!rt){
rt = ++tot, z[rt].size = 1, z[rt].w = x, z[rt].pos = rand();
return;
}
z[rt].size++;
int nxt = x < z[rt].w ? 0 : 1;
add(x, z[rt].ch[nxt]);
if(z[z[rt].ch[nxt]].pos<z[rt].pos)
rotate(rt, nxt);
}
inline void del(int x,int &rt){
if(z[rt].w==x){
if(z[rt].ch[0]*z[rt].ch[1]==0){
rt = z[rt].ch[0] + z[rt].ch[1];
return;
}
if(z[z[rt].ch[0]].pos>z[z[rt].ch[1]].pos){
rotate(rt, 1);
del(x, z[rt].ch[0]);
}else{
rotate(rt, 0);
del(x, z[rt].ch[1]);
}
}else{
int nxt = x < z[rt].w ? 0 : 1;
del(x, z[rt].ch[nxt]);
}
update(rt);
}
inline int find(int x,int rt){
if(!rt)
return 1;
if(z[rt].w>=x)
return find(x, z[rt].ch[0]);
else
return find(x, z[rt].ch[1]) + z[z[rt].ch[0]].size + 1;
}
inline int ask(int x,int rt){
if(z[z[rt].ch[0]].size==x-1)
return z[rt].w;
if(z[z[rt].ch[0]].size>=x)
return ask(x, z[rt].ch[0]);
else
return ask(x - z[z[rt].ch[0]].size - 1, z[rt].ch[1]);
}
inline int pre(int x,int rt){
if(!rt)
return -inf;
if(z[rt].w<x)
return max(z[rt].w, pre(x, z[rt].ch[1]));
return pre(x, z[rt].ch[0]);
}
inline int nxt(int x,int rt){
if(!rt)
return inf;
if(z[rt].w>x)
return min(z[rt].w, nxt(x, z[rt].ch[0]));
return nxt(x, z[rt].ch[1]);
}
} tr;
```
#### (2)<span id = "3.06.2">Splay</span>
Form 1:
**by yizimi**
```cpp
int rot, tot, n;
struct tree{
int ch[2], fa, cnt, w, size;
};
struct Splay{
tree z[mn];
void update(int rt){
z[rt].size = z[z[rt].ch[0]].size + z[z[rt].ch[1]].size + z[rt].cnt;
}
void rotate(int a){
int b = z[a].fa;
int c = z[b].fa;
int k = z[b].ch[1] == a;
z[c].ch[z[c].ch[1] == b] = a;
z[a].fa = c;
z[b].ch[k] = z[a].ch[k ^ 1];
z[z[a].ch[k ^ 1]].fa = b;
z[a].ch[k ^ 1] = b;
z[b].fa = a;
update(b), update(a);
}
void splay(int a,int goal){
while(z[a].fa!=goal){
int b = z[a].fa;
int c = z[b].fa;
if(c!=goal)
(z[b].ch[0] == a) ^ (z[c].ch[0] == b) ? rotate(a) : rotate(b);
rotate(a);
}
if (goal == 0)
rot = a;
}
void insert(int x){
int fa = 0, rt = rot;
while(rt && z[rt].w!=x){
fa = rt;
int nxt = x < z[rt].w ? 0 : 1;
rt = z[rt].ch[nxt];
}
if(rt)
z[rt].cnt++;
else{
rt = ++tot;
int nxt = x < z[fa].w ? 0 : 1;
if(fa)
z[fa].ch[nxt] = rt;
z[tot].ch[0] = 0, z[tot].ch[1] = 0, z[tot].fa = fa;
z[tot].w = x, z[tot].size = 1, z[tot].cnt = 1;
}
splay(rt, 0);
}
void find(int x){
int rt = rot;
if(!rt)
return;
//int nxt = x < z[rt].w ? 0 : 1;
//while(z[rt].ch[nxt] && x!=z[rt].w)
//nxt = x < z[rt].w ? 0 : 1, rt = z[rt].ch[nxt];
while (z[rt].ch[x > z[rt].w] && x != z[rt].w)
rt = z[rt].ch[x > z[rt].w];
splay(rt, 0);
}
int nxt(int x,int f){
find(x);
int rt = rot;
if((z[rt].w>x && f) || (z[rt].w<x && !f))
return rt;
rt = z[rt].ch[f];
while(z[rt].ch[f^1])
rt = z[rt].ch[f ^ 1];
return rt;
}
void del(int x){
int last = nxt(x, 0);
int next = nxt(x, 1);
splay(last, 0);
splay(next, last);
int t = z[next].ch[0];
if(z[t].cnt>1){
z[t].cnt--;
splay(t, 0);
}else{
z[next].ch[0] = 0;
}
}
int ask(int x){
int rt = rot;
if(z[rt].size<x)
return 0;
while(1119){
int b = z[rt].ch[0];
if(x>z[b].size+z[rt].cnt){
x -= z[b].size + z[rt].cnt;
rt = z[rt].ch[1];
}else if(z[b].size>=x)
rt = b;
else
return z[rt].w;
}
}
int findx(int x){
find(x);
return z[z[rot].ch[0]].size;
}
int query(int x,int f){
return z[nxt(x, f)].w;
}
} tr;
int main(){
tr.insert(-2147483647);
tr.insert(+2147483647);
n = read();
go(i,1,n,1){
int s = read(), x = read();
int ans;
if(s == 1) tr.insert(x);
if(s == 2) tr.del(x);
if(s == 3) ans = tr.findx(x);
if(s == 4) ans = tr.ask(x+1);
if(s == 5) ans = tr.query(x, 0);
if(s == 6) ans = tr.query(x, 1);
if(s > 2) cout << ans << "\n";
}
return 0;
}
```
Form 2:(pointer)
**by Rhein_E**
```cpp
// POJ Buy Tickets TLE
#include <cstdio>
#include <iostream>
#include <cstring>
struct Splay {
struct Node {
int val, size;
Node *child[2], *fa;
Node() { memset(this, 0, sizeof(Node)); }
} * root;
inline int getSize(Node *p) { return (p ? p->size : 0); }
void update(Node *rt) {
rt->size = 1;
rt->size += getSize(rt->child[0]);
rt->size += getSize(rt->child[1]);
}
void rotate(Node *rt) {
int d = (rt->fa->child[1] == rt);
Node *f = rt->fa;
f->child[d] = rt->child[d ^ 1];
if (rt->child[d ^ 1])
rt->child[d ^ 1]->fa = f;
rt->child[d ^ 1] = f;
if (f->fa)
f->fa->child[f->fa->child[1] == f] = rt;
rt->fa = f->fa;
f->fa = rt;
update(f);
update(rt);
}
void splay(Node *rt) {
while (rt->fa) {
if (!rt->fa->fa)
rotate(rt);
else if ((rt->fa->child[1] == rt) == (rt->fa->fa->child[1] == rt->fa)) {
rotate(rt->fa);
rotate(rt);
} else {
rotate(rt);
rotate(rt);
}
}
root = rt;
}
Node *query(int pos) {
Node *p = root;
if (pos > getSize(root))
return 0;
while (1) {
if (getSize(p->child[0]) + 1 == pos) {
splay(p);
return p;
} else if (getSize(p->child[0]) >= pos)
p = p->child[0];
else
pos -= getSize(p->child[0]) + 1, p = p->child[1];
}
}
Node *insert(int pos, int val) {
if (!root) {
root = new Node;
root->size = 1, root->val = val;
} else {
Node *p = query(pos), *np = new Node;
np->val = val, np->size = 1;
if (!p->child[1])
p->child[1] = np, np->fa = p;
else {
p = p->child[1];
while (p->child[0])
p = p->child[0];
p->child[0] = np, np->fa = p;
}
splay(np);
}
return root;
}
void clear() {
clear(root);
root = NULL;
}
void clear(Node *p) {
if (p->child[0])
clear(p->child[0]);
if (p->child[1])
clear(p->child[1]);
delete p;
}
} tree;
int N;
int main() {
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Rhein_E\\Desktop\\code\\cpp\\templates\\in.txt", "r", stdin);
freopen("C:\\Users\\Rhein_E\\Desktop\\code\\cpp\\templates\\out.txt", "w", stdout);
#endif
while (~scanf("%d", &N)) {
tree.insert(0, 0);
for (int i = 0; i < N; ++i) {
int a, b;
scanf("%d%d", &a, &b);
tree.insert(a + 1, b);
}
for (int i = 1; i <= N; ++i)
printf("%d ", tree.query(i + 1)->val);
puts("");
tree.clear();
}
return 0;
}
```
##### 文艺平衡树(Splay)
```cpp
int n, m, rot, tot = 0, a[mn];
struct tree{
int ch[2], w, sze, fa, col;
tree(int _w = 0, int _sze = 0, int _fa = 0, int _col = 0)
: w(_w), sze(_sze), fa(_fa), col(_col) { ch[0] = ch[1] = 0; }
};
struct Splay{
tree z[mn];
inline void update(int rt){
z[rt].sze = z[z[rt].ch[0]].sze + z[z[rt].ch[1]].sze + 1;
}
inline void change(int x){ //jiao huan zuo you zi shu
swap(z[x].ch[0], z[x].ch[1]);
}
inline void push_col(int rt){
if(z[rt].col){
z[z[rt].ch[0]].col ^= 1;
z[z[rt].ch[1]].col ^= 1;
z[rt].col = 0;
swap(z[rt].ch[0], z[rt].ch[1]);
}
}
inline int iden(int rt){
return z[z[rt].fa].ch[0] == rt ? 0 : 1;
}
inline void connect(int x,int y,int son){
z[x].fa = y;
z[y].ch[son] = x;
}
inline void rotate(int x){
int y = z[x].fa;
int moot = z[y].fa;
int yson = iden(x);
int mootson = iden(y);
int B = z[x].ch[yson ^ 1];
connect(B, y, yson), connect(y, x, yson ^ 1), connect(x, moot, mootson);
update(y), update(x);
}
inline void splay(int x,int &k){
if(x==k)
return;
int p = z[k].fa;
while(z[x].fa != p){
push_col(x); //warning
int y = z[x].fa;
if(z[y].fa != p) //warning
rotate(iden(x) ^ iden(y) ? x : y);
rotate(x);
}
k = x;
}
inline int findkth(int rt,int k){
while(1119){
push_col(rt);
if(z[rt].ch[0] && k <= z[z[rt].ch[0]].sze){
rt = z[rt].ch[0]/*,puts("okok")*/;
}else {
if(z[rt].ch[0])
k -= z[z[rt].ch[0]].sze;
if(!--k)
return rt;
rt = z[rt].ch[1];
}
}
}
inline int getRange(int l,int r,int &rt){
int x = findkth(rt, l);
//puts("getxok");
splay(x, rt);
//cout << rot << "\n";
int y = findkth(rt, r + 2);
int ooo = z[rt].ch[1];
splay(y, ooo);
return z[y].ch[0];
}
inline void modify(int &rt,int nowl,int nowr){
int x = getRange(nowl, nowr, rt);
z[x].col ^= 1;
update(z[rt].ch[1]), update(rt);
}
inline void build(int l,int r,int rt){
int m = (l + r) >> 1;
z[rt].w = a[m];
if(l <= m - 1) {
z[z[rt].ch[0] = ++tot].fa = rt;
build(l, m - 1, z[rt].ch[0]);
}
if(m + 1 <= r) {
z[z[rt].ch[1] = ++tot].fa = rt;
build(m + 1, r, z[rt].ch[1]);
}
update(rt);
}
inline void dfs(int rt){
if(rt == 0)
return;
push_col(rt);
//puts("push_colok");
dfs(z[rt].ch[0]);
if(z[rt].w > 0)
printf("%d ", z[rt].w);
dfs(z[rt].ch[1]);
}
} tr;
int main(){
n = read(), m = read();
go(i, 1, n, 1) a[i] = i;
rot = ++tot;
tr.build(0, n + 1, rot);
go(i,1,m,1){
int x = read(), y = read();
tr.modify(rot, x, y);
}
tr.dfs(rot);
return 0;
}
```
##### (3)<span id = "3.06.3">FHQ Treap</span>
```cpp
struct tree {
int ch[2], w, pri, sze;
} z[mn];
int cnt;
inline void update(int rt) {
z[rt].sze = 1;
if(z[rt].ch[0])
z[rt].sze += z[z[rt].ch[0]].sze;
if(z[rt].ch[1])
z[rt].sze += z[z[rt].ch[1]].sze;
}
inline int newnode(int w = 0) {
z[++cnt].sze = 1;
z[cnt].w = w;
z[cnt].pri = rand();
return cnt;
}
inline int merge(int x, int y) {
if(!x || !y) return x + y;
if(z[x].pri < z[y].pri) {
z[x].ch[1] = merge(z[x].ch[1], y);
update(x);
return x;
} else {
z[y].ch[0] = merge(x, z[y].ch[0]);
update(y);
return y;
}
}
inline void split(int rt, int k, int &x, int &y) {
if(!rt) x = y = 0;
else {
if(z[rt].w <= k) {
x = rt, split(z[rt].ch[1], k, z[rt].ch[1], y);
} else {
y = rt, split(z[rt].ch[0], k, x, z[rt].ch[0]);
}
update(rt);
}
}
inline int findkth(int rt, int k) {
while(1119) {
if(k <= z[z[rt].ch[0]].sze)
rt = z[rt].ch[0];
else if(k == z[z[rt].ch[0]].sze + 1){
return rt;
} else {
k -= z[z[rt].ch[0]].sze + 1, rt = z[rt].ch[1];
}
}
}
int n, rot, x, y;
inline void debug() {
go(i, 1, cnt, 1) {
printf("%d:%d %d %d\n", i, z[i].pri, z[i].sze, z[i].w);
}
}
int main() {
srand((unsigned)time(NULL));
n = read();
int zz;
go(i, 1, n, 1) {
int s = read(), a = read();
if(s == 1) {
split(rot, a, x, y);
rot = merge(merge(x, newnode(a)), y);
}
if(s == 2) {
split(rot, a, x, zz);
split(x, a - 1, x, y);
y = merge(z[y].ch[0], z[y].ch[1]);
rot = merge(merge(x, y), zz);
}
if(s == 3) {
split(rot, a - 1, x, y);
printf("%d\n", z[x].sze + 1);
rot = merge(x, y);
}
if(s == 4) {
printf("%d\n", z[findkth(rot, a)].w);
}
if(s == 5) {
split(rot, a - 1, x, y);
printf("%d\n", z[findkth(x, z[x].sze)].w);
rot = merge(x, y);
}
if(s == 6) {
split(rot, a, x, y);
printf("%d\n", z[findkth(y, 1)].w);
rot = merge(x, y);
}
// cout << x << " " << y << " " << zz << " " << rot << "\n";
// debug();
}
return 0;
}
```
##### 维护区间操作
```cpp
struct tree {
int sze, ch[2], pri, w;
ll x, sum, col;
} z[mn];
inline void update(int rt) {
z[rt].sze = 1, z[rt].sum = z[rt].x;
if(z[rt].ch[0])
z[rt].sze += z[z[rt].ch[0]].sze, z[rt].sum += z[z[rt].ch[0]].sum;
if(z[rt].ch[1])
z[rt].sze += z[z[rt].ch[1]].sze, z[rt].sum += z[z[rt].ch[1]].sum;
}
inline void push_col(int rt) {
if(z[rt].col) {
z[z[rt].ch[0]].x += z[rt].col;
z[z[rt].ch[1]].x += z[rt].col;
z[z[rt].ch[0]].col += z[rt].col;
z[z[rt].ch[1]].col += z[rt].col;
z[z[rt].ch[0]].sum += z[rt].col * z[z[rt].ch[0]].sze;
z[z[rt].ch[1]].sum += z[rt].col * z[z[rt].ch[1]].sze;
z[rt].col = 0;
}
}
int cnt;
inline int newnode(int w, int v = 0) {
z[++cnt].x = v;
z[cnt].w = w;
z[cnt].sze = 1;
z[cnt].sum = v;
z[cnt].pri = rand();
return cnt;
}
inline int merge(int x, int y) {
if(!x || !y) return x + y;
if(z[x].pri < z[y].pri) {
push_col(x);
z[x].ch[1] = merge(z[x].ch[1], y);
update(x);
return x;
} else {
push_col(y);
z[y].ch[0] = merge(x, z[y].ch[0]);
update(y);
return y;
}
}
inline void split(int rt, int k, int &x, int &y) {
if(!rt) x = y = 0;
else {
push_col(rt);
if(z[rt].w <= k) {
x = rt, split(z[rt].ch[1], k, z[rt].ch[1], y);
} else {
y = rt, split(z[rt].ch[0], k, x, z[rt].ch[0]);
}
update(rt);
}
}
int n, m;
int xx, yy, rot, zz;
int main(){
// fre();
n = read(), m = read();
go(i, 1, n, 1) {
int a = read();
split(rot, i, xx, yy);
rot = merge(merge(xx, newnode(i, a)), yy);
}
go(i, 1, m, 1) {
int s = read(), x = read(), y = read();
if(s == 1) {
ll v = read();
split(rot, y, xx, zz);
split(xx, x - 1, xx, yy);
z[yy].col += v;
z[yy].x += v;
z[yy].sum += z[yy].sze * v;
rot = merge(merge(xx, yy), zz);
} else {
split(rot, y, xx, zz);
split(xx, x - 1, xx, yy);
printf("%lld\n", z[yy].sum);
rot = merge(merge(xx, yy), zz);
}
}
return 0;
}
```
##### (4)<span id = "3.06.4">WBLT</span>
learn from dalao: **codesonic**
```cpp
int n, cnt, fa, rot;
int sze[mn << 2], ch[mn << 2][2], val[mn << 2];
inline void newnode(int &rt, int v) {
rt = ++cnt;
sze[rt] = 1, val[rt] = v;
}
inline void copynode(int x, int y) {
sze[x] = sze[y], ch[x][0] = ch[y][0],
ch[x][1] = ch[y][1], val[x] = val[y];
}
inline void merge(int l, int r) {
sze[++cnt] = sze[l] + sze[r];
val[cnt] = val[r];
ch[cnt][0] = l, ch[cnt][1] = r;
}
inline void rotate(int rt, bool flag) {
if(flag) {
merge(ch[rt][0], ch[ch[rt][1]][0]);
ch[rt][0] = cnt, ch[rt][1] = ch[ch[rt][1]][1];
} else {
merge(ch[ch[rt][0]][1], ch[rt][1]);
ch[rt][1] = cnt, ch[rt][0] = ch[ch[rt][0]][0];
}
}
inline void maintain(int rt) {
if(sze[ch[rt][0]] > sze[ch[rt][1]] * ratio)
rotate(rt, 0);
else if(sze[ch[rt][1]] > sze[ch[rt][0]] * ratio)
rotate(rt, 1);
}
inline void update(int rt) {
if(!sze[ch[rt][0]]) return;
sze[rt] = sze[ch[rt][0]] + sze[ch[rt][1]];
val[rt] = val[ch[rt][1]];
}
inline void insert(int rt, int x) {
if(sze[rt] == 1) {
newnode(ch[rt][0], min(x, val[rt]));
newnode(ch[rt][1], max(x, val[rt]));
update(rt);
return;
}
maintain(rt);
insert(x > val[ch[rt][0]] ? ch[rt][1] : ch[rt][0], x);
update(rt);
}
inline void erase(int rt, int x) {
if(sze[rt] == 1) {
rt = ch[fa][0] == rt ? ch[fa][1] : ch[fa][0];
copynode(fa, rt);
return;
}
maintain(rt);
fa = rt;
erase(x > val[ch[rt][0]] ? ch[rt][1] : ch[rt][0], x);
update(rt);
}
inline int find(int rt, int x) {
if(sze[rt] == x) return val[rt];
maintain(rt);
if(x > sze[ch[rt][0]])
return find(ch[rt][1], x - sze[ch[rt][0]]);
return find(ch[rt][0], x);
}
inline int rnk(int rt, int x) {
if(sze[rt] == 1) return 1;
maintain(rt);
if(x > val[ch[rt][0]])
return rnk(ch[rt][1], x) + sze[ch[rt][0]];
return rnk(ch[rt][0], x);
}
inline void solve() {
n = read();
newnode(rot, (1 << 30));
go(i, 1, n, 1) {
int s = read(), x = read();
if(s == 1) insert(rot, x);
if(s == 2) erase(rot, x);
if(s == 3) printf("%d\n", rnk(rot, x));
if(s == 4) printf("%d\n", find(rot, x));
if(s == 5) printf("%d\n", find(rot, rnk(rot, x) - 1));
if(s == 6) printf("%d\n", find(rot, rnk(rot, x + 1)));
}
}
int main(){
solve();
return 0;
}
```
#### 7.<span id = "3.07">权值线段树</span>
```cpp
ll z[mn << 2];
inline void update(int rt) {
z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
inline void build(int l, int r, int rt) {
if (l == r) { z[rt] = 0; return; }
int m = (l + r) >> 1;
build(lson); build(rson); update(rt);
}
inline void modify(int l, int r, int rt, ll x) {
if (l == r) { z[rt]++; return; }
int m = (l + r) >> 1;
if (x <= m) modify(lson, x);
else modify(rson, x);
update(rt);
}
inline ll query(int l, int r, int rt, int nowl, int nowr) {
if (nowl <= l && r <= nowr) { return z[rt]; }
int m = (l + r) >> 1;
if (nowl <= m) {
if (m < nowr) return query(lson, nowl, nowr) + query(rson, nowl, nowr);
else return query(lson, nowl, nowr);
} else {
return query(rson, nowl, nowr);
}
}
int a[mn], b[mn], n, m;
int main() {
n = read();
go(i, 1, n, 1) a[i] = b[i] = read();
sort(b + 1, b + n + 1);
int size = unique(b + 1, b + n + 1) - b - 1;
go(i, 1, n, 1) a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
build(1, 500000, 1);
ll ans = 0;
go(i, 1, n, 1) {
ans += query(root, a[i] + 1, 500000);
modify(root, a[i]);
}
cout << ans << "\n";
return 0;
}
```
#### 8.<span id = "3.08">主席树(可持久化(权值)线段树)</span>
```cpp
int n, q, m, cnt = 0;
int a[mn], b[mn];
int rot[mn];
struct node{
int l, r, sum;
explicit node(int _l = 0, int _r = 0, int _sum = 0)
: l(_l), r(_r), sum(_sum) {}
} z[mn << 5];
inline int build(int l,int r){
int rt = ++cnt;
z[rt].sum = 0;
int m = (l + r) >> 1;
if (l < r)
z[rt].l = build(l, m),
z[rt].r = build(m + 1, r);
return rt;
}
inline int modify(int l,int r,int pre,int x){
int rt = ++cnt;
z[rt].l = z[pre].l, z[rt].r = z[pre].r, z[rt].sum = z[pre].sum + 1;
int m = (l + r) >> 1;
if (l < r) {
if (x <= m)
z[rt].l = modify(l, m, z[pre].l, x);
else
z[rt].r = modify(m + 1, r, z[pre].r, x);
}
return rt;
}
inline int query(int l,int r,int k,int nowl,int nowr){
if(l>=r) return l;
int x = z[z[nowr].l].sum - z[z[nowl].l].sum;
int m = (l + r) >> 1;
if(x >= k) return query(l, m, k, z[nowl].l, z[nowr].l);
else return query(m + 1, r, k - x, z[nowl].r, z[nowr].r);
}
int main(){
n = read(), q = read();
go(i, 1, n, 1) a[i] = b[i] = read();
sort(b + 1, b + n + 1);
m = unique(b + 1, b + n + 1) - b - 1;
rot[0] = build(1, m);
go(i, 1, n, 1)
rot[i] = modify(1, m, rot[i - 1], lower_bound(b + 1, b + m + 1, a[i]) - b);
go(i, 1, q, 1) {
int x = read(), y = read(), z = read();
cout << b[query(1, m, z, rot[x - 1], rot[y])] << "\n";
}
return 0;
}
```
#### 9.<span id = "3.09">可持久化数组(可持久化线段树)</span>
```cpp
struct tree{
int l, r, w;
};
int a[mn], rot[mn];
struct PersistableSegmentTree{
tree z[mn << 5];
int cnt = 0;
inline void build(int l,int r,int &rt){
rt = ++cnt;
if(l==r){
z[rt].w = a[l];
return;
}
int m = (l + r) >> 1;
build(l, m, z[rt].l);
build(m + 1, r, z[rt].r);
}
inline void modify(int l,int r,int &rt,int pre,int now,int v){
rt = ++cnt;
z[rt].l = z[pre].l, z[rt].r = z[pre].r, z[rt].w = z[pre].w;
if(l==r){
z[rt].w = v;
return;
}
int m = (l + r) >> 1;
if(now<=m)
modify(l, m, z[rt].l, z[pre].l, now, v);
else
modify(m + 1, r, z[rt].r, z[pre].r, now, v);
}
inline int query(int l,int r,int rt,int now){
if(l==r)
return z[rt].w;
int m = (l + r) >> 1;
if(now<=m)
return query(l, m, z[rt].l, now);
else
return query(m + 1, r, z[rt].r, now);
}
} P_tr;
int n, m;
int main(){
n = read(), m = read();
go(i, 1, n, 1) a[i] = read();
P_tr.build(1, n, rot[0]);
go(i, 1, m, 1){
int pre = read(), s = read(), x = read();
if(s==1){
int v = read();
P_tr.modify(1, n, rot[i], rot[pre], x, v);
}else{
cout << P_tr.query(1, n, rot[pre], x) << "\n";
rot[i] = rot[pre];
}
}
return 0;
}
```
#### 10.<span id = "3.10">二维树状数组</span>
##### (1)单点修改,区间求和
```cpp
ll z[mn][mn], n, m, q;
inline int lb(int x) { return x & -x; }
inline void modify(int x, int y, ll v) {
for(int i = x; i <= n; i += lb(i))
for(int j = y; j <= m; j += lb(j))
z[i][j] += v;
}
inline ll query(int x, int y) {
ll ans = 0;
for(int i = x; i; i -= lb(i))
for(int j = y; j; j -= lb(j))
ans += z[i][j];
return ans;
}
int main() {
n = read(), m = read(), q = read();
go(i, 1, n, 1) go(j, 1, m, 1){
ll x = read(); modify(i, j, x);
}
go(i, 1, q, 1) {
int s = read(), x = read(), y = read();
if(s == 1) {
ll v = read();
modify(x, y, v);
} else if(s == 2){
int xx = read(), yy = read();
printf("%lld\n", query(xx, yy) - query(x - 1, yy) - query(xx, y - 1) + query(x - 1, y - 1));
}
}
return 0;
}
```
### 11.<span id = "3.11">扫描线</span>
#### POJ 1151 Atlantis——AC代码
```cpp
struct tree{
int mark; double sum;
} z[mn << 2];
struct seg{
double l, r, h;
int d;
seg() {}
seg(double _l, double _r, double _h, int _d) : l(_l), r(_r), h(_h), d(_d) {}
bool operator < (const seg &b) const { return h < b.h; }
} s[mn];
int n, num, kkk;
double ha[mn];
double x, y, xx, yy;
#define root 0, m - 1, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
inline void update(int l, int r, int rt) {
if(z[rt].mark) z[rt].sum = ha[r + 1] - ha[l];
else if(l == r) z[rt].sum = 0;
else z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
}
inline void modify(int l, int r, int rt, int nowl, int nowr, int d) {
if(nowl <= l && r <= nowr) {
z[rt].mark += d;
update(bson);
return;
}
int m = (l + r) >> 1;
if(nowl <= m) modify(lson, nowl, nowr, d);
if(m < nowr) modify(rson, nowl, nowr, d);
update(bson);
}
inline int search(double key, double* x, int n) {
int l = 0, r = n - 1;
while(l <= r) {
int m = (l + r) >> 1;
if(x[m] == key) return m;
if(x[m] > key) r = m - 1;
else l = m + 1;
}
return -1;
}
int main() {
while(cin >> n, n) {
num = 0;
go(i, 0, n - 1, 1) {
cin >> x >> y >> xx >> yy;
ha[num] = x;
s[num++] = seg(x, xx, y, 1);
ha[num] = xx;
s[num++] = seg(x, xx, yy, -1);
}
sort(ha, ha + num);
sort(s, s + num);
int m = 1;
go(i, 1, num - 1, 1)
if(ha[i] != ha[i - 1]) ha[m++] = ha[i];
double ans = 0;
go(i, 0, num - 1, 1) {
int L = search(s[i].l, ha, m);
int R = search(s[i].r, ha, m) - 1;
modify(root, L, R, s[i].d);
ans += z[1].sum * (s[i + 1].h - s[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n", ++kkk, ans);
}
return 0;
}
```
### 12.<span id = "3.12">可持久化平衡树</span>
```cpp
struct edge{
int ch[2], sze, pri;
ll w;
} z[mn * 50];
int rot[mn], xx, yy, zz, n, cnt;
inline void update(int rt) {
z[rt].sze = 1;
if(z[rt].ch[0]) z[rt].sze += z[z[rt].ch[0]].sze;
if(z[rt].ch[1]) z[rt].sze += z[z[rt].ch[1]].sze;
}
inline int newnode(ll w = 0) {
z[++cnt].w = w;
z[cnt].sze = 1;
z[cnt].pri = rand();
return cnt;
}
inline int merge(int x, int y) {
if(!x || !y) return x + y;
if(z[x].pri < z[y].pri) {
int rt = newnode();
z[rt] = z[x];
z[rt].ch[1] = merge(z[rt].ch[1], y);
update(rt);
return rt;
} else {
int rt = newnode();
z[rt] = z[y];
z[rt].ch[0] = merge(x, z[rt].ch[0]);
update(rt);
return rt;
}
}
inline void split(int rt, ll k, int &x, int &y) {
if(!rt) x = y = 0;
else {
if(z[rt].w <= k) {
x = newnode();
z[x] = z[rt];
split(z[x].ch[1], k, z[x].ch[1], y);
update(x);
} else {
y = newnode();
z[y] = z[rt];
split(z[y].ch[0], k, x, z[y].ch[0]);
update(y);
}
}
}
inline int findkth(int rt, int k) {
while(1119) {
if(k <= z[z[rt].ch[0]].sze)
rt = z[rt].ch[0];
else {
if(z[rt].ch[0]) k -= z[z[rt].ch[0]].sze;
if(!--k) return rt;
rt = z[rt].ch[1];
}
}
}
int main(){
n = read();
go(i, 1, n, 1) {
xx = yy = zz = 0;
int tmp = read(), s = read(); ll a = read();
rot[i] = rot[tmp];
if(s == 1) {
split(rot[i], a, xx, yy);
rot[i] = merge(merge(xx, newnode(a)), yy);
} else if(s == 2) {
split(rot[i], a, xx, zz);
split(xx, a - 1, xx, yy);
yy = merge(z[yy].ch[0], z[yy].ch[1]);
rot[i] = merge(merge(xx, yy), zz);
} else if(s == 3) {
split(rot[i], a - 1, xx, yy);
printf("%lld\n", z[xx].sze + 1);
rot[i] = merge(xx, yy);
} else if(s == 4) {
printf("%lld\n", z[findkth(rot[i], a)].w);
} else if(s == 5) {
split(rot[i], a - 1, xx, yy);
if(xx == 0) {
printf("-2147483647\n");
continue;
}
printf("%lld\n", z[findkth(xx, z[xx].sze)].w);
rot[i] = merge(xx, yy);
} else if(s == 6) {
split(rot[i], a, xx, yy);
if(yy == 0) {
printf("2147483647\n");
continue;
}
printf("%lld\n", z[findkth(yy, 1)].w);
rot[i] = merge(xx, yy);
}
}
return 0;
}
```
### 13.<span id = "3.13">树套树</span>
#### (1)<span id = "3.13.1">线段树套FHQ Treap</span>
```cpp
int ch[mn * 40][2], pri[mn * 40], sze[mn * 40], w[mn * 40];
int cnt, xx, yy, zz, rot[mn << 2], n, q;
int a[mn];
inline void treap_update(int rt) {
sze[rt] = 1;
if(ch[rt][0]) sze[rt] += sze[ch[rt][0]];
if(ch[rt][1]) sze[rt] += sze[ch[rt][1]];
}
inline int newnode(int ww = 0) {
w[++cnt] = ww;
sze[cnt] = 1;
pri[cnt] = rand();
return cnt;
}
inline int merge(int x, int y) {
if(!x || !y) return x + y;
if(pri[x] < pri[y]) {
ch[x][1] = merge(ch[x][1], y);
treap_update(x);
return x;
} else {
ch[y][0] = merge(x, ch[y][0]);
treap_update(y);
return y;
}
}
inline void split(int rt, int k, int &x, int &y) {
if(!rt) x = y = 0;
else {
if(w[rt] <= k)
x = rt, split(ch[rt][1], k, ch[rt][1], y);
else
y = rt, split(ch[rt][0], k, x, ch[rt][0]);
treap_update(rt);
}
}
inline int findkth(int rt, int k) {
if(sze[rt] < k || sze[rt] == 0 || k == 0) return -1;
while(1119) {
if(k <= sze[ch[rt][0]])
rt = ch[rt][0];
else {
if(ch[rt][0]) k -= sze[ch[rt][0]];
if(!--k) return rt;
rt = ch[rt][1];
}
}
}
inline void fhq_insert(int &rt, int a) {
int xx, yy;
split(rt, a, xx, yy);
rt = merge(merge(xx, newnode(a)), yy);
}
inline void fhq_delete(int &rt, int a) {
int xx, yy, zz;
split(rt, a, xx, zz);
split(xx, a - 1, xx, yy);
yy = merge(ch[yy][0], ch[yy][1]);
rt = merge(merge(xx, yy), zz);
}
inline int fhq_pre(int &rt, int a) {
int xx, yy, ans;
split(rt, a - 1, xx, yy);
int tmp = findkth(xx, sze[xx]);
if(tmp != -1)
ans = w[tmp];
else ans = -2147483647;
rt = merge(xx, yy);
return ans;
}
inline int fhq_suf(int &rt, int a) {
int xx, yy, ans;
split(rt, a, xx, yy);
int tmp = findkth(yy, 1);
if(tmp != -1)
ans = w[tmp];
else ans = 2147483647;
rt = merge(xx, yy);
return ans;
}
inline int fhq_find(int &rt, int a) {
int xx, yy, ans;
split(rt, a - 1, xx, yy);
ans = sze[xx];
rt = merge(xx, yy);
return ans;
}
// FHQ Treap ---------------------------------------------
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define root 1, n, 1
inline void build(int l, int r, int rt) {
go(i, l, r, 1)
fhq_insert(rot[rt], a[i]);
if(l == r) return ;
int m = (l + r) >> 1;
build(lson), build(rson);
}
inline void modify(int l, int r, int rt, int now, int v) {
fhq_delete(rot[rt], a[now]);
fhq_insert(rot[rt], v);
if(l == r) return ;
int m = (l + r) >> 1;
if(now <= m) modify(lson, now, v);
else modify(rson, now, v);
}
inline int query_rk(int l, int r, int rt, int nowl, int nowr, int v) {
if(nowl <= l && r <= nowr) {
return fhq_find(rot[rt], v);
}
int m = (l + r) >> 1;
if(nowl <= m) {
if(m < nowr) return query_rk(lson, nowl, nowr, v) + query_rk(rson, nowl, nowr, v);
else return query_rk(lson, nowl, nowr, v);
} else return query_rk(rson, nowl, nowr, v);
}
inline int query_pre(int l, int r, int rt, int nowl, int nowr, int v) {
if(nowl <= l && r <= nowr) {
return fhq_pre(rot[rt], v);
}
int m = (l + r) >> 1;
if(nowl <= m) {
if(m < nowr) return max(query_pre(lson, nowl, nowr, v), query_pre(rson, nowl, nowr, v));
else return query_pre(lson, nowl, nowr, v);
} else return query_pre(rson, nowl, nowr, v);
}
inline int query_suf(int l, int r, int rt, int nowl, int nowr, int v) {
if(nowl <= l && r <= nowr) {
return fhq_suf(rot[rt], v);
}
int m = (l + r) >> 1;
if(nowl <= m) {
if(m < nowr) return min(query_suf(lson, nowl, nowr, v), query_suf(rson, nowl, nowr, v));
else return query_suf(lson, nowl, nowr, v);
} else return query_suf(rson, nowl, nowr, v);
}
// Segment tree ----------------------------------------
int main() {
n = read(), q = read();
go(i, 1, n, 1) {
a[i] = read();
}
build(root);
go(i, 1, q, 1) {
int s = read(), x, y, v;
if(s == 1) {
x = read(), y = read(), v = read();
printf("%d\n", query_rk(root, x, y, v) + 1);
} else if(s == 2) {
x = read(), y = read(), v = read();
int l = 0, r = 1e8 + 5, ans = 0;
while(l <= r) {
int m = (l + r) >> 1;
if(query_rk(root, x, y, m) + 1 <= v)
ans = m, l = m + 1;
else r = m - 1;
}
printf("%d\n", ans);
} else if(s == 3) {
x = read(), v = read();
modify(root, x, v);
a[x] = v;
} else if(s == 4) {
x = read(), y = read(), v = read();
printf("%d\n", query_pre(root, x, y, v));
} else if(s == 5) {
x = read(), y = read(), v = read();
printf("%d\n", query_suf(root, x, y, v));
}
}
return 0;
}
```
#### 14.<span id = "3.14">分块</span>
```cpp
int n, m, blo = 888;
ll z[mn], col[mn], sum[mn]; int bl[mn];
inline void modify(int l, int r, ll v) {
go(i, l, min(bl[l] * blo, r), 1)
z[i] += v, sum[bl[l]] += v;
// sum[bl[l]] += (min(bl[l] * blo, r) - l + 1) * v;
if(bl[l] != bl[r]) {
go(i, (bl[r] - 1) * blo + 1, r, 1)
z[i] += v, sum[bl[r]] += v;
// sum[bl[r]] += (r - (bl[r] - 1) * blo) * v;
}
go(i, bl[l] + 1, bl[r] - 1, 1)
col[i] += v;
}
inline ll query(int l, int r) {
ll ans = 0;
go(i, l, min(bl[l] * blo, r), 1)
ans += (z[i] + col[bl[l]]);
if(bl[l] != bl[r])
go(i, (bl[r] - 1) * blo + 1, r, 1)
ans += (z[i] + col[bl[r]]);
go(i, bl[l] + 1, bl[r] - 1, 1)
ans += sum[i] + col[i] * blo;
// return ans % mod;
return ans;
}
int main() {
n = read(), m = read();
go(i, 1, n, 1) z[i] = read();
go(i, 1, n, 1) bl[i] = (i - 1) / blo + 1;
go(i, 1, n, 1) sum[bl[i]] += z[i];
go(i, 1, m, 1) {
int s = read(), l = read(), r = read(), v;
if(s == 1) v = read(), modify(l, r, v);
if(s == 2) printf("%lld\n", query(l, r));
}
// getchar();
return 0;
}
```
#### 15.<span id = "3.15">左偏树</span>
```cpp
int n, m, cnt;
int ch[mn][2], w[mn], fa[mn], dep[mn]; // 左偏树
bool vis[mn];
inline int findx(int x) { return x == fa[x] ? x : fa[x] = findx(fa[x]); }
inline int merge(int x, int y) {
if(!x || !y) return x + y;
if(w[x] > w[y] || (w[x] == w[y] && x > y)) swap(x, y);
ch[x][1] = merge(ch[x][1], y);
if(dep[ch[x][0]] < dep[ch[x][1]]) swap(ch[x][0], ch[x][1]);
dep[x] = dep[ch[x][1]] + 1;
fa[ch[x][0]] = fa[ch[x][1]] = x;
return x;
}
inline int del(int x) {
if(vis[x]) return -1;
vis[x] = 1;
int tmp = w[x];
fa[ch[x][0]] = ch[x][0];
fa[ch[x][1]] = ch[x][1];
fa[x] = merge(ch[x][0], ch[x][1]);
return tmp;
}
inline void solve() {
n = read(), m = read();
go(i, 1, n, 1) w[i] = read(), fa[i] = i;
go(i, 1, m, 1) {
int s = read(), x, y;
if(s == 1) {
x = read(), y = read();
if(!vis[x] && !vis[y]) merge(findx(x), findx(y));
} else {
x = read();
if(vis[x]) puts("-1");
else printf("%d\n", del(findx(x)));
}
}
}
```
#### 16.<span id = "3.16">珂朵莉树(ODT)</span>
```cpp
// using ll read()
inline ll mul(ll a, ll b, ll mod) {
a %= mod;
ll ans = 1ll;
for(; b; b >>= 1) {
if(b & 1) ans = a * ans % mod;
a = a * a % mod;
}
return ans % mod;
}
class ODT {
public:
struct tree {
int l, r;
mutable ll v;
tree(int _l, int _r = -1, ll _v = 0):
l(_l), r(_r), v(_v) {}
bool operator < (const tree &b) const {
return l < b.l;
}
};
#define IT std::set<tree>::iterator
IT split(int pos) {
IT it = s.lower_bound(tree(pos));
if(it != s.end() && it->l == pos) return it;
--it;
int l = it->l, r = it->r;
ll v = it->v;
s.erase(it);
s.insert(tree(l, pos - 1, v));
return s.insert(tree(pos, r, v)).first;
}
std::set<tree> s;
void assign(int l, int r, ll val = 0) {
IT itl = split(l), itr = split(r + 1);
s.erase(itl, itr);
s.insert(tree(l, r, val));
}
void add(int l, int r, ll val) {
IT itl = split(l), itr = split(r + 1);
for(; itl != itr; ++itl) itl->v += val;
}
ll query_rank(int l, int r, int rk) {
std::vector<std::pair<ll, int> > vp;
IT itl = split(l), itr = split(r + 1);
vp.clear();
for(; itl != itr; ++itl)
vp.push_back(std::pair<ll, int>(itl->v, itl->r - itl->l + 1));
sort(vp.begin(), vp.end());
for(std::vector<std::pair<ll, int> >::iterator it = vp.begin(); it != vp.end(); ++it) {
rk -= it->second;
if(rk <= 0) return it->first;
}
return -1ll;
}
ll query_sum(int l, int r, int ex, int mod) {
IT itl = split(l), itr = split(r + 1);
ll sum = 0ll;
for(; itl != itr; ++itl)
sum = (sum + (mul(itl->v, (ll)ex, (ll)mod) * (ll)(itl->r - itl->l + 1) % mod) % mod) % mod;
return sum;
}
} odt;
int n, m;
ll a[mn];
inline void solve() {
n = read(), m = read(), seed = read(), vmax = read();
go(i, 1, n, 1) {
a[i] = (rnd() % vmax) + 1;
odt.s.insert(ODT::tree(i, i, a[i]));
}
odt.s.insert(ODT::tree(n + 1, n + 1, 0ll));
// options below
}
inline void init() {
odt.s.clear();
}
```
## 四.其他
### (一)字符串算法
#### 1.<span id = "4.01.01">manacher算法</span>
##### P3805 【模板】manacher算法——AC代码
```cpp
char s[mn], str[mn];
int f[mn], l;
inline void manacher() {
int nowmid = 0, nowr;
for (int i = l; str[i] != 0; i++) str[i] = 0;
go(i, 1, l - 1, 1) {
if (nowmid > i) {
f[i] = min(f[nowr * 2 - i], f[nowr] + nowr - i);
} else f[i] = 1;
while (str[i + f[i]] == str[i - f[i]]) ++f[i];
if (i + f[i] > nowmid) {
nowmid = i + f[i];
nowr = i;
}
}
}
inline void init(char a) {
str[0] = a, str[1] = a;
go(i, 0, l - 1, 1) {
str[(i << 1) + 2] = s[i];
str[(i << 1) + 3] = a;
}
l = (l << 1) + 2;
str[l] = 0;
}
inline char huaji()
{
srand((unsigned)time(NULL));
int o = rand() % 120;
while ((o >= 'a' && o <= 'z') || (o >= 7 && o <= 10))
o = rand() % 120;
return char(o);
}
int main()
{
scanf("%s", s);
l = strlen(s);
char a = huaji();
init(a); manacher();
int ans = -1;
go(i, 0, l - 1, 1) ans = max(f[i], ans);
cout << ans - 1;
return 0;
}
```
#### 2.<span id = "4.01.02">Trie树</span>
```cpp
struct node {
int next[26];
bool exist;
node() {
exist = false;
memset(next, 0, sizeof(next));
}
} z[233333];
int cnt = 1;
inline void insert(char *s) {
int l = strlen(s + 1);
int p = root;
go(i, 1, l, 1) {
if (z[p].next[s[i] - 'a'] == 0) {
cnt++;
z[p].next[s[i] - 'a'] = cnt;
}
p = z[p].next[s[i] - 'a'];
}
z[p].exist = true;
}
inline bool query(char *s) {
int l = strlen(s + 1);
int p = root;
go(i, 1, l, 1) {
if (z[p].next[s[i] - 'a'] == 0) return false;
p = z[p].next[s[i] - 'a'];
}
return z[p].exist;
}
```
#### 3.字符串hash
##### (1)<span id = "4.01.03.1">自然溢出法</span>:P3370 【模板】字符转哈希——AC代码
```cpp
char s[ms];
int n, sum;
ull h[ms], bit[ms];
ull a[mn], t;
int main()
{
n = read();
bit[0] = 1;
go(i, 1, ms - 30, 1)
bit[i] = bit[i - 1] * base;
//采用自然炸裂法(逃
go(x, 1, n, 1) {
scanf("%s", s);
ull l = strlen(s);
go(i, 0, l - 1, 1)
h[i + 1] = h[i] * base + s[i];
a[x] = h[l];
}
sort(a + 1, a + n + 1);
go(i, 1, n, 1) {
if (t != a[i]) sum++;
t = a[i];
}
cout << sum << "\n";
return 0;
}
```
##### (2)<span id = "4.01.03.2">单模哈希法</span>:P3370 【模板】字符转哈希——80分代码
```cpp
char s[ms];
const ull p = 19260817;
int n, sum;
ull h[ms], bit[ms];
ull a[mn], t;
int main() {
n = read();
bit[0] = 1;
go(i, 1, ms - 30, 1)
bit[i] = (bit[i - 1] * base) % p;
//采用dan膜炸裂法(逃
go(x, 1, n, 1) {
scanf("%s", s);
ull l = strlen(s);
go(i, 0, l - 1, 1) {
h[i + 1] = (h[i] * base + s[i]) % p;
}
a[x] = h[l];
}
sort(a + 1, a + n + 1);
go(i, 1, n, 1) {
if (t != a[i]) sum++;
t = a[i];
}
cout << sum << "\n";
return 0;
}
```
##### (3)<span id = "4.01.03.3">双模哈希法</span>:P3370 【模板】字符转哈希——AC代码
```cpp
struct node {
ull x, y;
} a[mn];
char s[mn];
int n, ans = 1;
inline bool cmp(node a, node b) {
return a.x < b.x;
}
inline ull hash1(char s[]) {
int len = strlen(s);
ull ans = 0;
for (int i = 0; i < len; i++)
ans = (ans * base + (ull)s[i]) % mod1;
return ans;
}
inline ull hash2(char s[]) {
int len = strlen(s);
ull ans = 0;
for (int i = 0; i < len; i++)
ans = (ans * base + (ull)s[i]) % mod2;
return ans;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) {
scanf("%s", s);
a[i].x = hash1(s);
a[i].y = hash2(s);
}
sort(a + 1, a + n + 1, cmp);
for (int i = 2; i <= n; i++)
if (a[i].x != a[i - 1].x || a[i - 1].y != a[i].y)
ans++;
cout << ans;
}
```
#### 4.<span id = "4.01.04">KMP字符串匹配</span>
##### POJ 3461 乌力波————AC代码
```cpp
struct KMP{
int ne[mn], len;
inline void get_ne(char ch[]){
memset(ne, 0, sizeof 0);
ne[0] = ne[1] = 0;
len = strlen(ch);
go(i,1,len-1,1){
int x = ne[i];
while(x && ch[i] != ch[x])
x = ne[x];
ne[i + 1] = ch[i] == ch[x] ? x + 1 : 0;
}
}
inline int finds(char ch[], char s[]){
int x = 0, ans = 0;
for(int i = 0; s[i]; i++){
while(x && ch[x] != s[i])
x = ne[x];
if(ch[x] == s[i])
x++;
if(x == len)
ans++;
}
return ans;
}
inline void debug(){//附赠debug
go(i, 1, len, 1)
printf("ne[%d] = %d\n", i, ne[i]);
}
} worker;
char ch[mn], s[mn];
int T;
inline void init() {
memset(ch, 0, sizeof ch);
memset(s, 0, sizeof s);
}
int main(){
T = read();
while(T--) {
init();
scanf("%s%s", ch, s);
worker.get_ne(ch);
printf("%d\n", worker.finds(ch, s));
}
return 0;
}
```
##### P3375 【模板】KMP字符串匹配 ————AC代码
```cpp
struct KMP{
int len, ne[mn];
inline void get_ne(char ch[]) {
memset(ne, 0, sizeof ne);
ne[0] = ne[1] = 0;
len = strlen(ch);
go(i, 1, len - 1, 1) {
int x = ne[i];
while(x && ch[i] != ch[x])
x = ne[x];
ne[i + 1] = ch[i] == ch[x] ? x + 1 : 0;
}
}
inline int finds(char ch[], char s[]) {
int x = 0, ans = 0;
for(int i = 0; s[i]; i++){
while(x && ch[x] != s[i])
x = ne[x];
if(ch[x] == s[i])
x++;
if(x == len)
printf("%d\n", i - len + 2), ans++;
}
return ans;
}
inline void output() {
go(i, 1, len, 1)
printf("%d ", ne[i]);
puts("");
}
} kmp;
char ch[mn], s[mn];
int main() {
scanf("%s%s", s, ch);
kmp.get_ne(ch);
int ans = kmp.finds(ch, s);
kmp.output();
int _ = 0;
return ~~(0^_^0);
}
```
#### 5.<span id = "4.01.05">AC自动机</span>
**by Rhein_E**
```cpp
struct AC_Automaton {
struct Node {
Node *next[26], *fail;
int end;
Node() {
for (int i = 0; i < 26; ++i)
next[i] = 0;
end = 0, fail = 0;
}
} * root;
Node *que[MAXN];
int hd, tl;
AC_Automaton() { root = new Node; }
Node *insert(char *str) {
int len = strlen(str);
Node *p = root;
for (int i = 0; i < len; ++i) {
if (!p->next[str[i] - 'a']) p->next[str[i] - 'a'] = new Node;
p = p->next[str[i] - 'a'];
}
++p->end;
return p;
}
void build_fail() {
hd = tl = 0;
for (int i = 0; i < 26; ++i)
if (root->next[i]) root->next[i]->fail = root, que[tl++] = root->next[i];
while (hd < tl) {
Node *p = que[hd++];
for (int i = 0; i < 26; ++i)
if (p->next[i]) {
if (p->fail->next[i])
p->next[i]->fail = p->fail->next[i];
else
p->next[i]->fail = root;
que[tl++] = p->next[i];
} else
p->next[i] = p->fail->next[i];
}
}
int match(char *str) {
int len = strlen(str), res = 0;
Node *p = root;
for (int i = 0; i < len; ++i) {
if (p->next[str[i] - 'a'])
p = p->next[str[i] - 'a'];
else
p = root;
for (Node *q = p; q && ~q->end; q = q->fail)
res += q->end, q->end = -1;
}
return res;
}
} ac;
int n;
char s[MAXN], t[MAXN];
int main() {
scanf("%d", &n);
while (n--) {
scanf("%s", s);
ac.insert(s);
}
ac.build_fail();
scanf("%s", t);
printf("%d\n", ac.match(t));
return 0;
}
```
## 五、其他
#### 1.排序算法(暂且不在数论里)
##### (1)<span id = "5.01.01">归并排序</span>
```cpp
int a[mn], by[mn];
inline void msort(int *A, int x, int y, int *T) {
if (y - x > 1) {
int m = x + (y - x) / 2;
int p = x, q = m, i = x;
msort(A, x, m, T);
msort(A, m, y, T);
while (p < m || q < y) {
if (q >= y || (p < m && A[p] <= A[q]))
T[i++] = A[p++];
else
T[i++] = A[q++];
}
for (i, x, y - 1, 1) {
A[i] = T[i];
}
}
}
```
##### (2)<span id = "5.01.02">快速排序</span>
```cpp
int n, a[100005];
int qsort(int l, int r)
{
int i, j, mid, p;
i = l; j = r;
mid = a[(l + r) / 2];
do {
while (a[i] < mid) i++;
while (a[j] > mid) j--;
if (i <= j) {
p = a[i]; a[i] = a[j]; a[j] = p;
i++; j--;
}
} while (i <= j);
if (l < j) qsort(l, j);
if (i < r) qsort(i, r);
}
```
##### (3)<span id = "5.01.03">堆排序</span>
(见数据结构->[堆](#3.01))
##### (4)<span id = "5.01.04">冒泡排序</span>
```cpp
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n - i; j++)
if(a[j] > a[j + 1])
swap(a[j], a[j + 1]);
}
```
#### 2.<span id = "5.02">LCS(最长公共子序列)</span>
```cpp
int f[mn];
int a[mn], b[mn], c[mn];
int n, l;
int main() {
n = read();
go(i, 1, n, 1) a[i] = read(), c[a[i]] = i;
go(i, 1, n, 1) b[i] = read(), f[i] = inf;
f[0] = 0, l = 0;
go(i, 1, n, 1) {
int le = 0, ri = l, mid;
if (c[b[i]] > f[l]) f[++l] = c[b[i]];
else {
while (le < ri) {
mid = (le + ri) / 2;
if (f[mid] > c[b[i]])
ri = mid;
else
le = mid + 1;
}
f[le] = min(c[b[i]], f[le]);
}
}
cout << l;
return 0;
}
```
#### 3.<span id = "5.03">舞蹈链(Dancing_Links_X)</span>
**by Rhein_E**
```cpp
// luogu P4929
#include <cstdio>
#include <cstring>
#include <iostream>
const int MAXN = 1010;
struct Node {
Node *left, *right, *up, *down, *head; //指向四个方向和列的表头
int row, cnt; //记录行号(用于记录答案)及列元素个数
} *head, *cols[MAXN];
int mtx[MAXN][MAXN], n, m;
int ans[MAXN], top;
void init();
bool solve();
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
scanf("%d", &mtx[i][j]);
init();
if (solve()) {
//puts("One solution found:");
for (int i = 0; i < top; ++i) printf("%d ", ans[i] + 1);
puts("");
} else puts("No Solution!");
return 0;
}
void init() {
top = 0;
head = new Node;
for (int i = 0; i < m; ++i) {
cols[i] = new Node;
cols[i]->row = -1;
cols[i]->head = cols[i];
}
for (int i = 1; i < m; ++i) cols[i]->left = cols[i - 1];
for (int i = m - 2; i >= 0; --i) cols[i]->right = cols[i + 1];
cols[0]->left = head, head->right = cols[0];
cols[m - 1]->right = head, head->left = cols[m - 1];
Node *p[MAXN]; //记录列尾
for (int i = 0; i < m; ++i) p[i] = cols[i];
for (int i = 0; i < n; ++i) {
Node *nplast = NULL;
for (int j = 0; j < m; ++j)
if (mtx[i][j]) {
Node *np = new Node;
np->row = i;
//插入列中
np->up = p[j], p[j]->down = np;
np->down = p[j]->head, p[j]->head->up = np;
np->head = p[j]->head;
//插入行中
if (nplast) {
np->right = nplast->right;
nplast->right->left = np;
np->left = nplast, nplast->right = np;
} else {
np->left = np->right = np;
nplast = np;
}
p[j] = np;
++np->head->cnt;
}
}
}
bool solve() {
if (head->right == head) return 1; //还有列未被覆盖
// 找到元素个数最少的列,能有效降低复杂度
Node *c = head->right;
for (Node *p = c->right; p != head; p = p->right)
if (p->cnt < c->cnt) c = p;
for (Node *p = c->down; p != c; p = p->down) {//枚举选择的行
for (Node *pp = p->right; pp != p; pp = pp->right) { //相关的列
for (Node *ppc = pp->down; ppc != pp; ppc = ppc->down) { //包含相关列的行
if (ppc != pp->head)
for (Node *ppr = ppc->right; ppr != ppc; ppr = ppr->right) {
ppr->up->down = ppr->down, ppr->down->up = ppr->up;
--ppr->head->cnt;
}
}
pp->head->left->right = pp->head->right;
pp->head->right->left = pp->head->left;
}
for (Node *ppc = p->down; ppc != p; ppc = ppc->down) {
if (ppc != p->head)
for (Node *ppr = ppc->right; ppr != ppc; ppr = ppr->right) {
ppr->up->down = ppr->down, ppr->down->up = ppr->up;
--ppr->head->cnt;
}
}
p->head->left->right = p->head->right;
p->head->right->left = p->head->left;
// 记录答案,继续搜索
ans[top++] = p->row;
if (solve()) return 1;
--top;
// 撤销选择行的操作
for (Node *pp = p->right; pp != p; pp = pp->right) { //相关的列
for (Node *ppc = pp->down; ppc != pp; ppc = ppc->down) { //包含相关列的行
if (ppc != pp->head)
for (Node *ppr = ppc->right; ppr != ppc; ppr = ppr->right) {
ppr->up->down = ppr->down->up = ppr;
++ppr->head->cnt;
}
}
pp->head->left->right = pp->head->right->left = pp->head;
}
for (Node *ppc = p->down; ppc != p; ppc = ppc->down) {
if (ppc != p->head)
for (Node *ppr = ppc->right; ppr != ppc; ppr = ppr->right) {
ppr->up->down = ppr->down->up = ppr;
++ppr->head->cnt;
}
}
p->head->left->right = p->head->right->left = p->head;
}
return 0;
}
//Rhein_E
```
#### 希望可以有所帮助!