基础模板(二)
ST表 模板
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef vector<vector<ll>> VVI;
const int N = 500010;
const int logh = 18;
int n, m;
int s[N][logh], lgh[N];
void init() {
lgh[1] = 0, lgh[2] = 1;
for (int i = 3; i < N; i++) lgh[i] = lgh[i >> 1] + 1;
}
void st() {
for (int j = 1; j <= logh; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
s[i][j] = max(s[i][j - 1], s[i + (1 << j - 1)][j - 1]);
}
}
}
int query(int l, int r) {
int d = lgh[r - l + 1];
return max(s[l][d], s[r - (1 << d) + 1][d]);
}
inline int read(){
int x = 0, f = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - 48; ch = getchar(); }
return x * f;
} // 快读
int main()
{
// freopen("in.txt", "r", stdin);
// ios::sync_with_stdio(false);
// cin.tie(0);
n = read(); m = read();
init();
for (int i = 1; i <= n; i++) s[i][0] = read();
st();
while (m--) {
int l, r;
l = read(); r = read();
printf("%d\n", query(l, r));
}
return 0;
}
负环 模板
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef vector<vector<ll>> VVI;
const int N = 10010;
int e[N], ne[N], h[N], idx, w[N];
int st[N], dist[N], cnt[N];
int n, m;
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int spfa() {
queue<int> q;
q.push(1);
st[1] = true;
dist[1] = 0;
while (q.size()) {
auto d = q.front();
q.pop();
st[d] = false;
for (int i = h[d]; ~i; i = ne[i]) {
int j = e[i];
if (dist[j] > dist[d] + w[i]) {
dist[j] = dist[d] + w[i];
cnt[j] = cnt[d] + 1;
if (cnt[j] >= n) return true;
if (!st[j]) {
q.push(j);
st[j] = true;
}
}
}
}
return false;
}
int main()
{
// freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--) {
idx = 0;
memset(h, -1, sizeof h);
memset(dist, 0x3f, sizeof dist);
memset(st, false, sizeof st);
memset(cnt, 0, sizeof cnt);
cin >> n >> m;
while (m--) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
if (c >= 0) add(b, a, c);
}
cout << (spfa() ? "YES" : "NO") << endl;
}
return 0;
}
单调栈 模板
#include<bits/stdc++.h>
typedef long long ll;
const int N = 3e6 + 10;
const int MOD = 1e9 + 7;
using namespace std;
int a[N];
int out[N];
pair<int, int> s[N];
int hh = -1;
void push(pair<int, int> e) {
s[++hh] = e;
}
void pop() {
hh--;
}
pair<int,int> top() {
return s[hh];
}
int size() {
return hh + 1;
}
int main() {
// freopen("in.txt", "r", stdin);
// ios::sync_with_stdio(false);
// cin.tie(0);
int n;
scanf("%d", &n);
for (int i = n - 1; ~i; i--) scanf("%d", a + i);
for (int i = 0; i < n; i++) {
int d = a[i];
while (size() && top().first <= d) {
pop();
}
if (size()) out[i] = top().second;
else out[i] = 0;
push({ d,n - i });
}
for (int i = n - 1; ~i; i--) printf("%d ", out[i]);
return 0;
}
乘法逆元 模板
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef vector<vector<ll>> VVI;
const int N = 3e6 + 10;
ll inv[N];
int main(){
// freopen("in.txt", "r", stdin);
// ios::sync_with_stdio(false);
// cin.tie(0);
int n, p;
inv[1] = 1;
cin >> n >> p;
cout << 1 << endl;
for (int i = 2; i <= n; i++) inv[i] = (ll)(p - p / i) * inv[p % i] % p;
for (int i = 2; i <= n; i++) printf("%d\n", inv[i]);
return 0;
}
线段树1 模板
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N = 100010;
ll a[N];
struct node {
int l, r;
ll v;
ll lazy;
}tr[N << 2];
void pushup(int u) {
tr[u].v = tr[u << 1].v + tr[u << 1 | 1].v;
}
void pushdown(int u) {
auto &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
if (root.lazy) {
left.lazy += root.lazy;
left.v += ((ll)left.r - left.l + 1) * root.lazy;
right.lazy += root.lazy;
right.v += ((ll)right.r - right.l + 1) * root.lazy;
root.lazy = 0;
}
}
void build(int u, int l, int r) {
if (l >= r) tr[u] = { l,r,a[r],0 };
else {
tr[u] = { l,r };
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
ll query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) return tr[u].v;
pushdown(u);
ll res = 0;
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) res += query(u << 1, l, r);
if (r > mid) res += query(u << 1 | 1, l, r);
return res;
}
void modify(int u, int l,int r, int d) {
if (tr[u].l >= l && tr[u].r <= r) {
tr[u].v += ((ll)tr[u].r - tr[u].l + 1) * d;
tr[u].lazy += d;
}
else {
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, d);
if (r > mid) modify(u << 1 | 1, l, r, d);
pushup(u);
}
}
int main() {
// freopen("in.txt", "r",stdin);
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
while (m--) {
int op;
cin >> op;
if (op == 1) {
int l, r, d;
cin >> l >> r >> d;
modify(1, l, r, d);
}
else {
int l, r;
cin >> l >> r;
cout << query(1,l, r) << endl;
}
}
return 0;
}
裴蜀定理 模板
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 30;
int a[N];
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int main() {
// freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
if (a[i] < 0) a[i] = -a[i];
}
int ans = a[0];
for (int i = 1; i < n; i++) ans = gcd(ans, a[i]);
cout << ans << endl;
return 0;
}
树状数组1 模板
#include<bits/stdc++.h>
using namespace std;
const int N = 500010;
int a[N];
int tr[N];
int n, m;
int lowbit(int x) {
return x & -x;
}
void add(int x, int y) {
// 将第x个数字加上k
for (int i = x; i <= n; i += lowbit(i)) tr[i] += y;
}
int query(int x) {
int ans = 0;
for (; x; x -= lowbit(x)) ans += tr[x];
return ans;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
add(i, x);
}
while (m--) {
int d, x, y;
scanf("%d%d%d", &d, &x, &y);
if (d == 1) {
// 插入
add(x, y);
}
else {
int ans = query(y) - query(x - 1);
cout << ans << endl;
}
}
return 0;
}
三分法 模板
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
const double esp = 1e-6;
const int N = 20;
double a[N];
int n;
double f(double x) {
double res = 0;
for (int i = 0; i < n; i++) {
res = res * x + a[i];
}
return res;
}
int main() {
// freopen("in.txt", "r", stdin);
double l, r;
cin >> n >> l >> r;
++n;
for (int i = 0; i < n; i++) cin >> a[i];
while (l <= r - esp) {
double lm = l + (r - l) / 3;
double rm = r - (r - l) / 3;
if (f(lm) <= f(rm)) l = lm;
else r = rm;
}
printf("%.5lf", l);
return 0;
}
树状数组2 模板
#include<bits/stdc++.h>
using namespace std;
const int N = 500010;
typedef long long ll;
ll tr[N];
int n, m;
ll lowbit(ll x) {
return x & -x;
}
void add(ll x, ll y) {
// 将第x个数字加上k
for (ll i = x; i <= n; i += lowbit(i)) tr[i] += y;
}
ll query(int x) {
ll ans = 0;
for (; x; x -= lowbit(x)) ans += tr[x];
return ans;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
ll x;
scanf("%lld", &x);
add(i, x);
add(i + 1, -x);
}
while (m--) {
int d;
scanf("%d", &d);
if (d == 1) {
// 插入
ll l, r, k;
scanf("%lld%lld%lld", &l, &r, &k);
add(l, k);
add(r + 1, -k);
}
else {
ll x;
scanf("%lld", &x);
printf("%lld\n", query(x));
}
}
return 0;
}
矩阵快速幂 模板
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
typedef long long ll;
typedef vector<vector<ll>> VVI;
VVI v;
const int MOD = 1e9 + 7;
VVI mul(VVI &a,VVI &b) {
VVI res(a);
for (int i = 0; i < a.size(); i++) {
for (int j = 0; j < a.size(); j++) {
res[i][j] = 0;
}
}
int n = a.size();
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
res[i][j] = (res[i][j] + a[i][k] * b[k][j] % MOD) % MOD;
}
}
}
return res;
}
VVI matqmi(VVI a, ll b) {
VVI res = a;
for (int i = 0; i < a.size(); i++) {
for (int j = 0; j < a.size(); j++) {
res[i][j] = (i == j);
}
}
while (b) {
if (b & 1) {
res = mul(res, a);
}
a = mul(a, a);
b >>= 1;
// cout << b << endl;
}
return res;
}
int main()
{
// freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
ll n, k;
cin >> n >> k;
VVI a;
a.resize(n);
for (int i = 0; i < n; i++) {
a[i].resize(n);
for (int j = 0; j < n; j++) {
cin >> a[i][j];
}
}
auto res = matqmi(a, k);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << res[i][j] << ' ';
}
cout << endl;
}
return 0;
}
矩阵加速(数列)模板
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N = 2e9 + 10;
const int MOD = 1e9 + 7;
void mul(int a[3][3], int b[3][3]) {
ll t[3][3] = { 0 };
for (int k = 0; k < 3; k++) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
t[i][j] = (t[i][j] + ((ll)a[i][k] * b[k][j]) % MOD) % MOD;
}
}
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
a[i][j] = t[i][j];
}
}
}// 矩阵乘法 令 a = a * b
int mul2(int s[3][1], int mat[3][3]){
ll t[3][3] = { 0 };
for (int k = 0; k < 3; k++) {
for (int i = 0; i < 1; i++) {
for (int j = 0; j < 3; j++) {
t[i][j] = (t[i][j] + ((ll)s[i][k] * mat[k][j]) % MOD) % MOD;
}
}
}
return t[0][0];
}// 矩阵乘法 返回s * mat 的第一个元素
int solve(int x) {
x--;
int s[3][1] = { 1,1,1 };
int mat[3][3] = {
0,0,1,
1,0,0,
0,1,1
};// 矩阵构造
int res[3][3] = {
1,0,0,
0,1,0,
0,0,1
};// 构造单位矩阵 相当于快速幂当中的 int res = 1;
while (x) {
if (x & 1) mul(res, mat);// 等价于 res = res * a;
mul(mat, mat);// 等价于 a *= a;
x >>= 1;
}
return mul2(s, res);
}
int main() {
// freopen("in.txt", "r",stdin);
ios::sync_with_stdio(false);
cin.tie(0);
int m;
cin >> m;
while (m--) {
int x;
cin >> x;
cout << solve(x) << endl;
}
return 0;
}
KMP字符串匹配 模板
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
char s[N], p[N];
int ne[N];
int n, m;
void getNext() {
for (int i = 2, j = 0; i <= n; i++) {
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j++;
ne[i] = j;
}
}
int main() {
// freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
cin >> s + 1 >> p + 1;
s[0] = p[0] = 1;
n = strlen(p) - 1;
m = strlen(s) - 1;
getNext();
for (int i = 1, j = 0; i <= m; i++) {
while (j && s[i] != p[j + 1])j = ne[j];
if (s[i] == p[j + 1])j++;
if (j == n) {
cout << i - n + 1 << endl;
j = ne[j];
}
}
for (int i = 1; i <= n; i++) {
cout << ne[i] << " ";
}
return 0;
}
最近公共祖先(LCA)模板
#include <bits/stdc++.h>
using namespace std;
const int N = 500010;
int e[N << 1], ne[N << 1], h[N], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int dep[N << 1], f[N][22];// 20层节点
void dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
for (int i = 1; (1 << i) <= dep[u]; i++) {
f[u][i] = f[f[u][i - 1]][i - 1];
}
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (fa == j) continue;
f[j][0] = u;
dfs(j, u);
}
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 20; ~i; i--) {
if (dep[f[x][i]] >= dep[y])
x = f[x][i];
if (x == y) return x;
}
for (int i = 20; ~i; i--) {
if (f[x][i] != f[y][i]) {
x = f[x][i], y = f[y][i];
}
}
return f[x][0];
}
int main() {
// freopen("in.txt", "r", stdin);
memset(h, -1, sizeof h);
int n, m, s;
scanf("%d%d%d", &n, &m, &s);
for (int i = 0; i < n - 1; i++) {
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(s,0);
while (m--) {
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", lca(a, b));
}
return 0;
}
滑动窗口 / 单调队列(sliding window) 模板
#include<bits/stdc++.h>
typedef long long ll;
const int N = 3e6 + 10;
const int MOD = 1e9 + 7;
using namespace std;
int a[N], q[N];
int hh = 0, tt = -1;
int main() {
// freopen("in.txt", "r", stdin);
// ios::sync_with_stdio(false);
// cin.tie(0);
int n,k;
scanf("%d%d", &n,&k);
for (int i = 0; i < n; i++) scanf("%d", a + i);
for (int i = 0; i < n; i++) {
if (hh <= tt && i - k + 1 > q[hh]) hh++;
while (hh <= tt && a[q[tt]] >= a[i]) tt--;
q[++tt] = i;
if (i >= k - 1) printf("%d ", a[q[hh]]);
}
puts("");
hh = 0, tt = -1;
for (int i = 0; i < n; i++) {
if (hh <= tt && i - k + 1 > q[hh]) hh++;
while (hh <= tt && a[q[tt]] <= a[i]) tt--;
q[++tt] = i;
if (i >= k - 1) printf("%d ", a[q[hh]]);
}
return 0;
}
单源最短路径(标准版)模板
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
vector<vector<PII> > h;
int dist[100010];
int st[100010];
int s;
void algorithm(){
priority_queue<PII,vector<PII>, greater<PII> > q;
memset(dist,0x3f,sizeof dist);
dist[s] = 0;//从s号点出发
int n = h.size();
q.push({0,s});// dist s
while(q.size()){
auto f = q.top();
int pos = f.second;
q.pop();
// cout << pos << endl;
if(st[pos]) continue;
for(auto e : h[pos]){
// 枚举(初始点)所有临边
int idx = e.first;//目标点
if(dist[idx] > dist[pos] + e.second){
dist[idx] = dist[pos] + e.second;
if(!st[idx]) q.push({dist[idx],idx});
}
}
st[pos] = 1;
}
// for(int i = 1; i <= n ; i ++){
// if(dist[i] == 0x3f3f3f3f) dist[i] = 2147483647;
// }
}
int main(){
int n,m;
cin >> n >> m >> s;
h.resize(n + 1);
for(int i = 0 ; i < m ; i ++){
int u,v,w;
cin >> u >> v >> w;
h[u].push_back({v,w});
}// 邻接表存图成功
algorithm();
for(int i = 1 ; i <= n ; i ++) cout << dist[i] << " ";
return 0;
}
备注(小技巧)
从文件中读入数据的方法
freopen("in.txt", "r", stdin);
从当前目录下读取 in.txt ,并且输入到 stdin 中,这就省去了多次粘贴数据的过程,提交的时候需要把这一行注释掉,不然会触发各种奇奇怪怪的错误。
加快 cin 读入速度的方法
ios::sync_with_stdio(false);
cin.tie(0);
可以显著加快 cin 的读入速度,不过遇到大数据量还是不太行,要用 scanf ,所以上面二点代码我会注释掉这两句话,然后把 cin 换成 scanf ,实际上还有比 scanf更快的快读,在上面的ST表中有用到,但是我不用这个,一般的题目 cin 足矣(主要是写起来方便)。
需要注意的是,用了这个加快读入的方法之后,就不能使用 scanf printf gets一类的东西了,否则输出顺序可能会发生未知变化,可以简单理解为输出快慢不一样导致的BUG。
这是第二阶段的模板,选手需要熟练记忆并尝试理解其内涵。