模板题
- P3378 【模板】堆
- P3367 【模板】并查集
- P1177 【模板】快速排序
- P3383 【模板】线性筛素数
- P3370 【模板】字符串哈希
- P3366 【模板】最小生成树
- P1226 【模板】快速幂||取余运算
- P3371 【模板】单源最短路径(弱化版)
- P3865 【模板】ST表
- P5788 【模板】单调栈
- P3811 【模板】乘法逆元
- P4549 【模板】裴蜀定理
- P3372 【模板】线段树 1
- P3374 【模板】树状数组 1
- P3390 【模板】矩阵快速幂
- P3382 【模板】三分法
- P3368 【模板】树状数组 2
- P1939 【模板】矩阵加速(数列)
- P3375 【模板】KMP字符串匹配
- P3379 【模板】最近公共祖先(LCA)
- P1886 滑动窗口 /【模板】单调队列
- P4779 【模板】单源最短路径(标准版)
- P2197 【模板】nim游戏
- P5367 【模板】康托展开
- P3373 【模板】线段树 2
- P5431 【模板】乘法逆元2
- P5905 【模板】Johnson 全源最短路
- P1439 【模板】最长公共子序列
- P5656 【模板】二元一次不定方程(exgcd)
数学
快速幂
ll ksm(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;
}
图论
LCA
code:
void dfs(int u) { // 倍增预处理
for(int i = 1; i <= 21; i++) f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = h[u]; i; i = e[i].nex) {
if(e[i].to == f[u][0]) continue;
f[e[i].to][0] = u; de[e[i].to] = de[u] + 1;
dfs(e[i].to);
}
}
void make_it() { // 另一种倍增预处理
de[s] = 1; f[s][0] = s;
dfs(s);
// for(int j = 1; j <= 21; j++)
// for(int i = 1; i <= n; i++)
// f[i][j] = f[f[i][j - 1]][j - 1]; 不在DFS中处理完f数组而是在这里处理也是可以的
}
int query(int x, int y) { // 查询
if(de[x] < de[y]) swap(x, y);
for(int i = 21; i >= 0; i--) if(de[x] - (1 << i) >= de[y]) x = f[x][i];
if(x == y) return x;
for(int i = 21; i >= 0; i--) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
缩点
Tarjan
传送门:P3387 【模板】缩点
code:
void tarjan(int u) { // tarjan核心代码
low[u] = dfn[u] = ++dfncnt; sta.push(u);
for(int i = h[u]; i; i = e[i].nex) {
int v = e[i].to;
if(!dfn[v]) {tarjan(v); low[u] = min(low[u], low[v]);}
else if(!scc[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
scccnt++;
while(sta.top() != u) {p[scccnt] += a[sta.top()]; scc[sta.top()]= scccnt; siz[scccnt]++; sta.pop();}
p[scccnt] += a[sta.top()]; scc[sta.top()] = scccnt; siz[scccnt]++; sta.pop();
}
}
void MakeScc() { // 缩点,建立缩点后的图
for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
for(int i = 1; i <= m; i++) {
int x = scc[e[i].from], y = scc[e[i].to];
if(x != y) addd(x, y);
}
}
数据结构
ST表
传送门1:P3865 【模板】ST表
传送门2:ST 表-OI Wiki
操作:查询区间最大值。
code:
void Pre() { // log_2(x) 预处理对数
logn[1] = 0; logn[2] = 1;
for(int i = 3; i <= 100005; i++) logn[i] = logn[i >> 1] + 1;
}
void SetUp { // 建表
pre();
for(int i = 1; i <= n; i++) f[i][0] = a[i];
for(int j = 1; j <= 21; 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]);
}
void query(int x, int y) { // 查询
int s = logn[y - x + 1];
printf("%d\n", max(f[x][s], f[y - (1 << s) + 1][s]));
}
树状数组
树状数组1
传送门1:P3374 【模板】树状数组 1
传送门2:树状数组-OI Wiki
操作:
- 将某一个数加上\(x\)
- 求出某区间每一个数的和
code:
int lowbit(int x) {return x & -x;}
void build() {
for(int i = 1; i <= n; i++) {
t[i] = t[i] + c[i];
int j = i + lowbit(i);
if(j <= n) t[j] = t[j] + t[i];
}
}
void update(int x, int k) {
while(x <= n) {
t[x] = t[x] + k;
x = x + lowbit(x);
}
}
int query(int x) {
int ans = 0;
while(x) {
ans = ans + t[x];
x = x - lowbit(x);
}
return ans;
}
树状数组2
转送门:P3368 【模板】树状数组 2
操作:
- 将某区间每一个数数加上\(x\)。
- 求出某一个数的值。
code:
ll lowbit(ll x) {return x & -x;}
void build() {
for(ll i = 1; i <= n; i++) {
t[i] = 0;
ll j = i + lowbit(i);
if(j <= n) t[j] = t[j] + t[i];
}
}
void update(ll x, ll k) {
while(x <= n) {
t[x] = t[x] + k;
x = x + lowbit(x);
}
}
ll query(ll x) {
ll ans = 0;
while(x) {
ans = ans + t[x];
x = x - lowbit(x);
}
return ans;
}
线段树
线段树1
传送门:P3372 【模板】线段树 1
操作:
- 将某区间每一个数加上 \(k\)。
- 求出某区间每一个数的和。
code:
void build(ll u, ll l, ll r) {
if(l == r) {
tre[u].sum = read();
return ;
}
ll lson = u << 1, rson = (u << 1) + 1, mid = (l + r) >> 1;
build(lson, l, mid); build(rson, mid + 1, r);
tre[u].sum = tre[lson].sum + tre[rson].sum;
}
void pushdown(ll u, ll l, ll r) {
if(tre[u].lazy == 0 || l == r) return;
ll lson = (u << 1), rson = (u << 1) + 1, mid = (l + r) >> 1;
tre[lson].lazy += tre[u].lazy; tre[lson].sum = tre[lson].sum + tre[u].lazy * (mid - l + 1);
tre[rson].lazy += tre[u].lazy; tre[rson].sum = tre[rson].sum + tre[u].lazy * (r - mid);
tre[u].lazy = 0;
}
void update(ll u, ll l, ll r, ll x, ll y, ll k) {
if(l >= x && r <= y) {
tre[u].lazy = tre[u].lazy + k;
tre[u].sum = tre[u].sum + k * (r - l + 1);
return ;
}
ll lson = u << 1, rson = (u << 1) + 1, mid = (l + r) >> 1;
pushdown(u, l, r);
if(x <= mid) update(lson, l, mid, x, y, k);
if(y > mid) update(rson, mid + 1, r, x, y, k);
tre[u].sum = tre[lson].sum + tre[rson].sum;
}
ll query(ll u, ll l, ll r ,ll x, ll y) {
if(l >= x && r <= y) return tre[u].sum;
ll lson = u << 1, rson = (u << 1) + 1, mid = (l + r) >> 1, t1 = 0, t2 = 0;
pushdown(u, l ,r);
if(x <= mid) t1 = query(lson, l, mid, x, y);
if(y > mid) t2 = query(rson, mid + 1, r, x, y);
return t1 + t2;
}
线段树2
传送门:P3373 【模板】线段树 2
操作:
- 将某区间每一个数乘上\(x\)
- 将某区间每一个数加上\(x\)
- 求出某区间每一个数的和
code:
void build(int tre,int l,int r) {
t[tre].lazy2 = 1;
if(l == r) {
t[tre].sum = read() % p;
return ;
}
int mid = (l + r) >> 1;
build(lson,l,mid); build(rson,mid + 1,r);
t[tre].sum = (t[lson].sum + t[rson].sum) % p;
}
void pushdown(int tre,int l,int r) {
int mid = (l + r) >> 1;
t[lson].lazy1 = (t[lson].lazy1 * t[tre].lazy2 + t[tre].lazy1) % p;
t[rson].lazy1 = (t[rson].lazy1 * t[tre].lazy2 + t[tre].lazy1) % p;
t[lson].lazy2 = (t[lson].lazy2 * t[tre].lazy2) % p;
t[rson].lazy2 = (t[rson].lazy2 * t[tre].lazy2) % p;
t[lson].sum = ((t[lson].sum * t[tre].lazy2) % p + (t[tre].lazy1 * (mid - l + 1)) % p) % p;
t[rson].sum = ((t[rson].sum * t[tre].lazy2) % p + (t[tre].lazy1 * (r - mid)) % p) % p;
t[tre].lazy1 = 0; t[tre].lazy2 = 1;
}
void updata1(int tre,int l,int r,int x,int y,int z) {
if(l >= x && r <= y) {
t[tre].sum = (t[tre].sum + (r - l + 1) * z) % p;
t[tre].lazy1 = (t[tre].lazy1 + z) % p;
return ;
}
pushdown(tre,l,r);
int mid = (l + r) >> 1;
if(x <= mid) updata1(lson,l,mid,x,y,z);
if(y > mid) updata1(rson,mid + 1,r,x,y,z);
t[tre].sum = (t[lson].sum + t[rson].sum) % p;
}
void updata2(int tre,int l,int r,int x,int y,int z) {
if(l >= x && r <= y) {
t[tre].sum = (t[tre].sum * z) % p;
t[tre].lazy1 = (t[tre].lazy1 * z) % p;
t[tre].lazy2 = (t[tre].lazy2 * z) % p;
return ;
}
pushdown(tre,l,r);
int mid = (l + r) >> 1;
if(x <= mid) updata2(lson,l,mid,x,y,z);
if(y > mid) updata2(rson,mid + 1,r,x,y,z);
t[tre].sum = (t[lson].sum + t[rson].sum) % p;
}
int query(int tre,int l,int r,int x,int y) {
if(l >= x && r <= y) return t[tre].sum;
pushdown(tre,l,r);
int mid = (l + r) >> 1,t1 = 0,t2 = 0;
if(x <= mid) t1 = query(lson,l,mid,x,y);
if(y > mid) t2 = query(rson,mid + 1,r,x,y);
return (t1 + t2) % p;
}