模板汇总

模板汇总

也许是中学生涯最后一次打板子了呀...


KMP模式匹配

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1000005;
char a[N], b[N];
int a1, b1, Next[N];
int main(){
	cin >> a + 1;
	cin >> b + 1;
	a1 = strlen(a + 1);
	b1 = strlen(b + 1);
	Next[1] = 0;
	for(int i = 2, j = 0; i <= b1; i++){
		while( j > 0 && b[j + 1] != b[i] ) j = Next[j];
		if( b[i] == b[j + 1] ) j++;
		Next[i] = j;
	}
	for(int i = 1, j = 0; i <= a1; i++){
		while( j > 0 && a[i] != b[j + 1]) j = Next[j];
		if(a[i] == b[j + 1]) j++;
		if(j == b1) {
			cout << i - j + 1 <<"\n";
			j = Next[j];
		}
	}
	for(int i = 1; i <= b1; i++) cout << Next[i] <<" ";
	return 0;
} 

Trie字典树

#include<iostream>
#include<cstdio>
using namespace std;
int Trie[N][27], end[p] = 1, tot = 1;
void insert(char* str){
	int len = strlen(str), p = 1;
	for(int k = 0; k < len; k++){
		int ch = str[k] - 'a';
		if(trie[p][ch] == 0) trie[p][ch] = ++tot;
		p = trie[p][ch];
	}
	end[p] = 1;
}
bool search(char* str){
	int len = strlen(str), p = 1;
	for(int k = 0; k < len; k++){
		p = trie[p][str[k]];
		if(p == 0) return 0;
	}
	return end[p];
}

ST表

值得注意的是,log函数最好配强制类型转换(不然poj会编译错误),转换的时候要用括号把log全部括一下,初始化的时候k要加一。初始化的时候j从0开始我被坑了无数次了

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 100005;
int a[N][30], n, m, k;
int read(){
	int x = 0, ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x;
}
int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++) a[i][0] = read();
	k = int(log(n) / log(2) + 1);
	for(int i = 1; i <= k; i++)
	    for(int j = 0; j <= n - (1 << i) + 1; j++)
	        a[j][i] = max(a[j][i - 1], a[j + (1 << (i-1))][i - 1]);
	while(m--){
		int x = read(), y = read();
		k = int(log(y - x + 1) / log(2));
		cout << max(a[x][k], a[y - (1 << k) + 1][k]) << "\n";
	}
	return 0;
}


单源最短路径 \(dijkstra\)

注意打标记和判重都在取出队头的时候进行

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N = 500005;
int ver[N], head[N], Next[N], edge[N], tot;
int n, m, s;
void add(int x, int y, int z){
	ver[++tot] = y, edge[tot] = z;
	Next[tot] = head[x], head[x] = tot; 
}
int read(){
	int x = 0, ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x;
}

/*Dijkstra*/
int d[N], v[N];
void dijkstra(int s){
	memset(d, 0x3f, sizeof d);
	memset(v, 0, sizeof v);
	priority_queue< pair< int, int > > q;
	q.push(make_pair(0, s)); d[s] = 0;
	while(q.size()){
		int x = q.top().second; q.pop();
		if(v[x]) continue;
		v[x] = 1;
		for(int i = head[x]; i; i = Next[i]){
			int y = ver[i], z = edge[i];
			if(d[y] > d[x] + z){
				d[y] = d[x] + z;
				q.push(make_pair(-d[y], y));
			}
		}
	}
}
int main(){
	cin >> n >> m >> s;
	for(int i = 1; i <= m; i++){
		int x = read(), y = read(), z = read();
		add(x, y, z);
	}
	dijkstra(s);
	for(int i = 1; i <= n; i++){
		if(d[i] == 0x3f3f3f3f)
			cout << "2147483647 ";
		else cout << d[i] <<" ";
	}
	return 0;
}

单源最短路径\(SPFA\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N = 500005;
int ver[N], head[N], Next[N], edge[N], tot;
int n, m, s;
void add(int x, int y, int z){
	ver[++tot] = y, edge[tot] = z;
	Next[tot] = head[x], head[x] = tot; 
}
int read(){
	int x = 0, ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x;
}
int d[N], v[N];
/* spfa */
void spfa(int s){
	memset(d, 0x3f, sizeof d);
	memset(v, 0, sizeof v);
	queue<int> q;
	q.push(s); v[s] = 1; d[s] = 0;
	while(q.size()){
		int x = q.front(); q.pop();
		v[x] = 0;
		for(int i = head[x]; i; i = Next[i]){
			int y = ver[i], z = edge[i];
			if(d[y] > d[x] + z){
				d[y] = d[x] + z;
				if(!v[x]) q.push(y), v[y] = 1;
			}
		}
	}
}
int main(){
	cin >> n >> m >> s;
	for(int i = 1; i <= m; i++){
		int x = read(), y = read(), z = read();
		add(x, y, z);
	}
	spfa(s);
	for(int i = 1; i <= n; i++){
		if(d[i] == 0x3f3f3f3f)
			cout << "2147483647 ";
		else cout << d[i] <<" ";
	}
	return 0;
}

扩展欧几里得

\(x = \frac{c}{d}x_0 + k \frac{b}{d}, y = \frac {c}{d}y_0 - k \frac{a}{d}\)

#include<iostream>
#define ll long long 
using namespace std;
int exgcd1(int a, int b, int &x, int &y){
	if(b == 0) {
		x = 1, y = 0;
		return a;
	}
	int d = exgcd1(b, a % b, x, y);
	int z = x; x = y, y = z - (a / b) * y;
	return d;
}
ll exgcd(ll a, ll b, ll &x, ll &y){
	if(b == 0){
		x = 1, y = 0;
		return a;
	} 
	int d = exgcd(b, a % b, x, y);
	int z = x; x = y, y = z - (a / b) * y;
	return d;
}
int main(){
	ll a, b, x, y, d;
	cin >> a >> b;
	d = exgcd(a, b, x, y);
	cout << (x % (b / d) + (b / d)) % (b / d) <<"\n";
	return 0;
}

最近公共祖先 LCA

  • 树上倍增法
    敲这个板子出了一堆错误。所以要记得空间开到两倍,lca的大于等于号。
    错的太智障了
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 1000005;
int ver[N], head[N], Next[N], tot;
int n, m, s, k, f[N][25], d[N];
void add(int x, int y){
	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
}
void bfs(){
	queue<int> q;
	q.push(s); d[s] = 1; 
	while(q.size()){
		int x = q.front(); q.pop();
		for(int i = head[x]; i; i = Next[i]){
			int y = ver[i];
			if(d[y]) continue;
			d[y] = d[x] + 1;
			f[y][0] = x;
			for(int j = 1; j <= k; j++)
				f[y][j] = f[f[y][j - 1]][j - 1];
			q.push(y);
		}
	}
}
int lca(int x, int y){
	if(d[y] < d[x]) swap(x, y);
	for(int i = k; i >= 0; i--)
		if(d[f[y][i]] >= d[x]) y = f[y][i];
	if(x == y) return x;
	for(int i = k; i >= 0; i--)
	    if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}

int read(){
	int x = 0, ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x;
}
int main(){
	cin >> n >> m >> s;
	k = (int)( log(n) / log(2) ) + 1;
	for(int i = 1; i < n; i++) {
		int x = read(), y = read();
		add(x, y), add(y, x);
	}
	bfs();
	while(m--){
		int x = read(), y = read();
		cout << lca(x, y) <<"\n";
	}
	
	return 0;
}

  • 树链剖分法
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1000005;
int ver[N], head[N], Next[N], tot;
int d[N], son[N], f[N], top[N], v[N], size[N];
int n, m, s;
void add(int x, int y){
	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
}

void dfs1(int x){
	v[x] = 1;
	size[x] = 1;
	for(int i = head[x]; i; i = Next[i]){
		int y = ver[i];
		if(v[y]) continue;
		d[y] = d[x] + 1;
		dfs1(y);
		f[y] = x;
		size[x] += size[y];
		if(!son[x] || size[y] > size[son[x]])
			son[x] = y;
	}
}
void dfs2(int x, int p){
	top[x] = p;
	if(son[x]) dfs2(son[x], p);
	for(int i = head[x]; i; i = Next[i]){
		int y = ver[i];
		if(y == f[x] || y == son[x]) continue;
		dfs2(y, y);
	}
}
int lca(int x, int y){
	while(top[x] != top[y]) 
		if(d[top[x]] > d[top[y]]) x = f[top[x]];
		else y = f[top[y]];
	if(d[x] > d[y]) return y;
	return x;
} 
int read(){
	int x = 0, ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x;
}
int main(){
	cin >> n >> m >> s;
	for(int i = 1; i < n; i++) {
		int x = read(), y = read();
		add(x, y), add(y, x);
	}
	d[s] = 1;
	dfs1(s);
	dfs2(s, s);
	while(m--){
		int x = read(), y = read();
		cout << lca(x, y) <<"\n";
	}
	return 0;
}

最小生成树 Kruskal

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 200005;
int n, m, f[N], ans = 0;
struct node{
	int x, y, z;
}edge[N];
bool cmp(node a, node b){
	return a.z < b.z;
}
int get(int x){
	if(x == f[x]) return x;
	return f[x] = get(f[x]);
}
int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++) f[i] = i;
	for(int i = 1; i <= m; i++){
		cin >> edge[i].x >> edge[i].y >> edge[i].z;
	}
	sort(edge + 1, edge + m + 1, cmp);
	for(int i = 1; i <= m; i++){
		int x = edge[i].x, y = edge[i].y;
		x = get(x), y = get(y);
		if(x == y) continue;
		f[x] = y;
		ans += edge[i].z;
	}
	cout << ans;
	return 0;
}

树的直径

void dp(int x){
	v[x] = 1;
	for(int i = head[x]; i; i = Next[i]){
		int y = ver[i];
		if(v[y]) continue;
		dp(y);
		ans = max(ans, d[x] + d[y] + edge[i]);
		d[x] = max(d[x], d[y] + edge[i]);
	}
}

树状数组

OI生涯学的第一个数据结构!
板子超好写,难在分析题目中能用前缀和、差分解决的地方。

void update(int x, int y){
	for(; x <= n; x += x & -x)
		s[x] += y;
}
int getsum(int x){
	int ans = 0;
	for(; x; x -= x & -x)
		ans += s[x];
	return ans;
}

归并排序

\(mid - i + 1\)背下来就好啦

#include<iostream>
using namespace std;
int a[100005], b[100005], ans;
void merge_sort(int l, int r){
	if(l == r) return;
	int mid = (l + r) >> 1;
	merge_sort(l, mid);
	merge_sort(mid + 1, r);
	int i = l, j = mid + 1, k = l;
	while(i <= mid || j <= r){
		if(j > r || ( a[i] <= a[j] && i <= mid ))
			b[k++] = a[i++];
		else 
		    b[k++] = a[j++], ans += mid - i + 1;
	}
	for(int i = l; i <= r; i++)
		a[i] = b[i];
}
int main(){
	int n;
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];
	merge_sort(1, n);
	cout << ans;
	return 0;
}

乘法逆元

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 3000005;
long long a[N], n, p;
int main(){
	cin >> n >> p; 
	a[0] = a[1] = 1;
	cout << 1 <<"\n";
	for(int i = 2; i <= n; i++){
		a[i] = (p - p / i) * a[p % i] % p;
		cout << a[i] <<"\n";
	} 

	return 0;
}

卢卡斯定理

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1000005;
long long a[N];
long long n, m, p;

long long fp(long long a, long long b){
	long long ans = 1;
	for(; b; b >>= 1){
		if(b & 1) ans = ans * a % p;
		a = a * a % p;
	}
	
	return ans;
}


long long C(long long n, long long m){
	if(n < m) return 0;
	return (a[n] * fp(a[m], p - 2)) % p * fp(a[n - m], p - 2) % p ;
}
long long Lucas(long long n, long long m){
	if(m == 0) return 1;
	return C(n % p, m % p) * Lucas(n / p, m / p) % p;
}

int read(){
	int x = 0, ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x;
}



int main(){
//	for(int i = 2; i < p; i++) a[i] = (p - p / i) * a[p % i] % p;
	
	int t = read();
	while(t--){
		n = read(), m = read(), p = read();
		a[0] = 1;
		for(int i = 1; i <= p; i++) a[i] = a[i - 1] * i % p;
		cout << Lucas(n + m, n) <<"\n";
	}
	
	
	return 0;
}

线段树

一个暑假的记忆,大概是我最有把握的模板了吧。

#include<iostream>
#include<cstdio>
using namespace std;
const int SIZE = 100005;
struct SegmentTree{
	int l, r;
	long long sum, add;
}t[SIZE * 4];
int a[SIZE];
void build(int p, int l, int r){
	t[p].l = l, t[p].r = r;
	if(l == r) {
		t[p].sum = a[l];
		return ;
	}
	int mid = (l + r) >> 1;
	build(p*2, l, mid);
	build(p*2+1, mid + 1, r);
	t[p].sum = t[p*2].sum + t[p*2+1].sum;
}
void spread(int p){
	if(t[p].add){
		t[p*2].sum += (long long)(t[p*2].r - t[p*2].l + 1) * t[p].add;
		t[p*2+1].sum += (long long)(t[p*2+1].r - t[p*2+1].l + 1) * t[p].add;
		t[p*2].add += t[p].add;
		t[p*2+1].add += t[p].add;
		t[p].add = 0;
	}
}
void change(int p, int l, int r, int val){
	if(l <= t[p].l && r >= t[p].r){
		t[p].add += val;
		t[p].sum += (long long)(t[p].r - t[p].l + 1) * val;
		return;
	}
	spread(p);
	int mid = (t[p].l + t[p].r) >> 1;
	if(l <= mid) change(p*2, l, r, val);
	if(r > mid) change(p*2+1, l, r, val);
	t[p].sum = t[p*2].sum + t[p*2+1].sum; 
}
long long ask(int p, int l, int r){
	if(l <= t[p].l && r >= t[p].r) return t[p].sum;
	spread(p);
	int mid = (t[p].l + t[p].r) >> 1;
	long long val = 0;
	if(l <= mid) val += ask(p*2, l, r);
	if(r > mid) val += ask(p*2+1, l, r);
	return val;
}
int main(){
	int n, m;
	cin >> n >> m;
	for(int i = 1; i <= n; i++) cin >> a[i];
	build(1, 1, n);
	while(m--){
		int f, x, y, h;
		cin >> f >> x>> y;
		if(f == 1){
			cin >> h;
			change(1, x, y, h);
		}
		if(f == 2){
			cout << ask(1, x, y) <<"\n";
		}
	}
	return 0;
}

并查集

板子不重要,路径压缩和带权才重要

int get(int x){
	if(x == fa[x]) return x;
	return fa[x] = get(fa[x]);
}
void merge(int x, int y){
	fa[get(x)] = get(y);
}

平衡树Treap

#include<iostream>
#include<cstdlib>
using namespace std;
const int SIZE = 100005;
struct Treap{
	int l, r;
	int val, dat;
	int size, cnt;
}a[SIZE];
int tot, root, n, INF=0x7fffffff;

int New(int val){
	a[++tot].val = val;
	a[tot].dat = rand();
	a[tot].size = a[tot].cnt = 1;
	return tot;
}

void Update(int p){
	a[p].size = a[a[p].l].size + a[a[p].r].size + a[p].cnt;
}

void Build(){
	New(-INF), New(INF);
	root = 1, a[1].r = 2;
	Update(root);
}

void zig(int &p){
	int q = a[p].l;
	a[p].l = a[q].r, a[q].r = p, p = q;
	Update(a[p].r), Update(p);
}

void zag(int &p){
	int q = a[p].r;
	a[p].r = a[q].l, a[q].l = p, p = q;
	Update(a[p].l), Update(p); 
}

void Insert(int &p, int val){
	if(p == 0){
		p = New(val);
		return;
	}
	if(a[p].val == val){
		a[p].cnt++, Update(p);
		return;
	}
	if(val < a[p].val){
		Insert(a[p].l, val);
		if(a[p].dat < a[a[p].l].dat) zig(p);
	}
	else{
		Insert(a[p].r, val);
		if(a[p].dat < a[a[p].r].dat) zag(p);
	}
	Update(p); 
}

int GetRankByVal(int p, int val){
	if(p == 0) return 0;
	if(val == a[p].val) return a[a[p].l].size;
	if(val < a[p].val) return GetRankByVal(a[p].l, val);
	return a[a[p].l].size + a[p].cnt + GetRankByVal(a[p].r, val);
}

int GetValByRank(int p, int rank){
	if(p == 0) return INF;
	if(a[a[p].l].size >= rank) return GetValByRank(a[p].l, rank);
	if(a[a[p].l].size + a[p].cnt >= rank) return a[p].val;
	return GetValByRank(a[p].r, rank - a[a[p].l].size - a[p].cnt);
}

int GetPrev(int val){
	int ans = 1;
	int p = root; 
	while(p){
		if(val == a[p].val){
			if(a[p].l > 0){
				p = a[p].l;
				while(a[p].r > 0) p = a[p].r;
				ans = p;
			}
			break;
		}
		if(a[ans].val < a[p].val && a[p].val < val) ans = p;
		p = val < a[p].val ? a[p].l : a[p].r;
	}
	return a[ans].val;
}
int GetNext(int val){
	int ans = 2;
	int p = root;
	while(p){
		if(val == a[p].val){
			if(a[p].r > 0){
				p = a[p].r;
				while(a[p].l > 0) p = a[p].l;
				ans = p;
			}
			break;
		}
		if(a[ans].val > a[p].val && a[p].val > val) ans = p;
		p = val < a[p].val ? a[p].l : a[p].r;
	}
	return a[ans].val;
}

void Remove(int &p, int val){
	if(p == 0) return;
	if(val == a[p].val){
		if(a[p].cnt > 1){
			a[p].cnt--, Update(p);
			return;
		}
		if(a[p].l || a[p].r){
			if(a[p].r == 0 && a[a[p].l].dat > a[a[p].r].dat)
				zig(p), Remove(a[p].r, val);
			else
			    zag(p), Remove(a[p].l, val);
			Update(p);
		}else p = 0;
		return;
	}
	val < a[p].val ? Remove(a[p].l, val) : Remove(a[p].r, val);
	Update(p);
}
int main(){
	Build();
	cin >> n;
	while(n--){
		int opt, x;
		cin >> opt >> x;
		switch(opt){
			case 1:
				Insert(root, x);
				break;
			case 2:
				Remove(root, x);
				break;
			case 3:
				cout << GetRankByVal(root, x) - 1 <<"\n";
				break;
			case 4:
				cout << GetValByRank(root, x+1) <<"\n";
				break;
			case 5:
				cout << GetPrev(x) <<"\n";
				break;
			case 6:
				cout << GetNext(x) <<"\n";
				break;
		}	
	}
	return 0;
}

平衡树Splay

#include<iostream>
using namespace std;

const int _ = 100005;
const int INF = 0x7fffffff;

int n, opt, x;

struct Spaly{
	int root, tot, cnt[_], val[_], size[_], ch[_][2], fa[_];
	
	bool chk(int x){
		return ch[fa[x]][1] == x;
	}
	
	void pushup(int x){
		if(!x) return;
		size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x]; 
	}
	
	int newnode(int x){
		val[++tot] = x;
		cnt[tot] = size[tot] = 1;
		ch[x][0] = ch[x][1] = 0;
		return tot;
	}
	
	void rotate(int x){
		int y = fa[x], z = fa[y], k = chk(x), w = ch[x][k^1];
		ch[y][k] = w, fa[w] = y;
		ch[z][chk(y)] = x, fa[x] = z;
		ch[x][k^1] = y, fa[y] = x;
		pushup(y), pushup(x);
	}
	
	void splay(int x, int goal = 0){
		while(fa[x] != goal){
			int y = fa[x], z = fa[y];
			if(z != goal){
				if(chk(x) == chk(y)) rotate(y);
				else rotate(x);
			}
			rotate(x);
		}
		if(!goal) root = x;
	}
	
	void insert(int x){
		int cur = root, p = 0;
		while(cur && x != val[cur]) 
			p = cur, cur = ch[cur][x > val[cur]];
		if(cur) ++cnt[cur], splay(cur);
		else cur = ch[p][x > val[p]] = newnode(x), fa[cur] = p, splay(cur);
	}
	
	void find(int x){
		if(!root) return;
		int cur = root;
		while(ch[cur][x > val[cur]] && x != val[cur]) cur = ch[cur][x > val[cur]];
		splay(cur);
	}
	
	int rank(int x){
		find(x);
		return cnt[ch[root][0]] + 1;
	}
	
	int kth(int k){
		int cur = root;
		while(1){
			if(ch[cur][0] && k <= size[ch[cur][0]]) cur = ch[cur][0];
			else if(k > size[ch[cur][0]] + cnt[cur]) k -= size[ch[cur][0]] + cnt[cur], cur = ch[cur][1];
			else return cur;
		}
	}
	
	int pre(int x){
		find(x);
		if(val[root] < x) return root;
		int cur = ch[root][0];
		while(ch[cur][1]) cur = ch[cur][1];
		return cur;
	}
	
	int next(int x){
		find(x);
		if(val[root] > x) return root;
		int cur = ch[root][1];
		while(ch[cur][0]) cur = ch[cur][0];
		return cur; 
	}
	
	void remove(int x){
		int u = pre(x), v = next(x);
		splay(u), splay(v, u);
		int w = ch[v][0];
		if(cnt[w] > 1) --cnt[w], splay(w);
		else size[0] = cnt[0] = ch[v][0] = 0;
	}
	
	void maintain(int x){
		if(!ch[x][0] && !ch[x][1]) size[x] = cnt[x];
		if(ch[x][0]) maintain(ch[x][0]);
		if(ch[x][1]) maintain(ch[x][1]);
		pushup(x);
	}
	
}T;

int main(){
	T.insert(-INF), T.insert(INF);
	cin >> n;
	for(int i=1; i<=n; i++){
		cin >> opt >> x;
		if(opt == 1) T.insert(x);
		if(opt == 2) T.remove(x);
		if(opt == 3) cout << T.rank(x) - 1 <<"\n";
		if(opt == 4) cout << T.val[T.kth(x)+1] <<"\n";
		if(opt == 5) cout << T.val[T.pre(x)] <<"\n";
		if(opt == 6) cout << T.val[T.next(x)] <<"\n";
	}	
	
	return 0;
}
posted @ 2019-11-15 20:25  hélium  阅读(445)  评论(0编辑  收藏  举报