基础模板(LV2)

基础模板(二)

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。

这是第二阶段的模板,选手需要熟练记忆并尝试理解其内涵。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值