小周猪猪De算法模板

1 tarjan算法

1.1 割点算法
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5;

int n, cnt, root, m, res;
int low[N], dfn[N], cut[N];
vector < int > a[N];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s * 10 + c - 48, c = getchar();
	return w ? -s : s;  
}

void tarjan(int x)
{
	int flag = 0;
	low[x] = dfn[x] = ++ cnt;
	for (int i=0;i<a[x].size();++i)
	{
		int y = a[x][i];
		if (dfn[y] == 0)
		{
			tarjan(y);
			low[x] = min(low[x], low[y]);
			if (dfn[x] <= low[y]) {
				flag ++;
				if (flag > 1 || x != root) cut[x] = 1;
			}
		}
		else low[x] = min(low[x], dfn[y]);
	}
	return;
}

int main(void)
{
	n = read(), m = read();
	for (int i=1;i<=m;++i)
	{
		int x = read(), y = read();
		a[x].push_back(y);
		a[y].push_back(x);
	}
	for (int i=1;i<=n;++i)
		if (dfn[i] == 0) root = i, tarjan(i);
	for (int i=1;i<=n;++i) res += cut[i]; 
	printf("%d\n", res);
	for (int i=1;i<=n;++i)
		if (cut[i]) printf("%d ", i);
	return 0; 
}
1.2 割边算法
#include <bits/stdc++.h>

using namespace std;
const int N = 5e5;

int n, m, tot = 1, cnt, k;
int Link[N], low[N], dfn[N], B[N * 2];
pair< int, int > t[N * 2];
struct node 
{
	int x, y, next;
} e[N * 2];

void add(int x, int y) {
	e[++ tot] = {x, y, Link[x]};
	Link[x] = tot; 
}

int read(void)
{
	int x; scanf("%d", &x);
	return x;
}

void tarjan(int x, int last)
{
	low[x] = dfn[x] = ++ cnt;
	for (int i=Link[x];i;i=e[i].next)
	{
		int y = e[i].y;
		if (dfn[y] == 0)
		{
			tarjan(y, i);
			low[x] = min(low[x], low[y]);
			if (dfn[x] < low[y]) B[i] = B[i ^ 1] = 1;
		}
		else if ((i^1) != last) low[x] = min(low[x], dfn[y]);
	}
	return;
}

int main(void)
{
	freopen("danger.in","r",stdin);
	freopen("danger.out","w",stdout); 
	n = read(), m = read();
	for (int i=1;i<=m;++i)
	{
		int x = read(), y = read();
		add(x, y);
		add(y, x);
	}
	for (int i=1;i<=n;++i)
		if (dfn[i] == 0) tarjan(i, 0);
	for (int i=2;i<=tot;i+=2)
		if (B[i]) t[++ k] = {min(e[i].x,e[i].y),max(e[i].x,e[i].y)};
	sort(t+1,t+k+1);
	for (int i=1;i<=k;++i)
		printf("%d %d\n", t[i].first, t[i].second);
	return 0;
}
1.3 强连通分量
#include <bits/stdc++.h>

using namespace std;
const int N = 3e5;

int n, m, scc, cnt, top;
int low[N], in[N], dfn[N], st[N], col[N], siz[N];
vector < int > a[N];

int read(void) {
	int x; scanf("%d", &x);
	return x;
}

void tarjan(int x)
{
	low[x] = dfn[x] = ++ cnt;
	in[x] = 1, st[++ top] = x;
	for (int i=0;i<a[x].size();++i)
	{
		int y = a[x][i];
		if (dfn[y] == 0) 
		{
			tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if (in[y]) low[x] = min(low[x], dfn[y]);
	}
	if (low[x] == dfn[x])
	{
		int y; scc ++;
		do y = st[top --], in[y] = 0, col[y] = scc, siz[scc] ++;
		while (x != y);
	} 
	return;
}

int main(void)
{
	freopen("popular.in","r",stdin);
	freopen("popular.out","w",stdout);
	n = read(), m = read();
	for (int i=1;i<=m;++i)
	{
		int x = read(), y = read();
		a[x].push_back(y);
	}
	for (int i=1;i<=n;++i)
		if (dfn[i] == 0) tarjan(i);
	for (int i=1;i<=n;++i)
		for (int j=0;j<a[i].size();++j)
			if (col[i] != col[a[i][j]]) in[col[i]] ++;
	int Now = 0, p = 0;
	for (int i=1;i<=scc;++i)
		if (in[i] == 0) Now ++, p = i;
	if (Now > 1) cout << 0 << endl;
	else cout << siz[p] << endl;
	return 0; 
}

2 最小生成树

2.1 B算法
#include <bits/stdc++.h>

using namespace std;
const int N = 3e5;

int n, m, res = 0;
int fa[N], Min[N], p[N];
vector < pair<int, int> > a[N];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

int get(int x) {
	if (fa[x] == x) return x;
	return fa[x] = get(fa[x]);
}

int main(void)
{
	n = read(), m = read();
	for (int i=1;i<=m;++i)
	{
		int x = read(), y = read(), v = read();
		a[x].push_back({y, v});
		a[y].push_back({x, v});	
	}	
	for (int i=1;i<=n;++i) fa[i] = i;
	while (true)
	{
		int flag = 0;
		for (int i=1;i<=n;++i) Min[i] = 1e9;
		for (int x=1;x<=n;++x)
		{
			for (int i=0;i<a[x].size();++i)
			{
				int y = a[x][i].first;
				int v = a[x][i].second;
				if (get(x) == get(y)) continue;
				if (v < Min[get(x)]) {
					Min[get(x)] = v;
					p[get(x)] = y;
				} 
			}
		}
		for (int i=1;i<=n;++i)
		{
			if (get(i) != get(p[i]) && Min[i] < 1e9) 
			{
				res += Min[i], flag = 1;
				fa[get(i)] = get(p[i]);
			}
		}
		if (flag == 0) break;
	}
	cout << res << endl;
	return 0;
} 
2.2 Prim算法
#include <bits/stdc++.h>

using namespace std;
const int N = 3e5;

int n, m, res;
int vis[N], dis[N];
vector < pair<int, int> > a[N];
priority_queue < pair<int, int> > q;

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

void Prim(void)
{
	memset(vis, 0, sizeof vis);
	memset(dis, 30, sizeof dis);
	q.push({dis[1] = 0, 1});
	while (q.size())
	{
		int x = q.top().second; q.pop();
		if (vis[x]) continue; vis[x] = 1;
		res += dis[x];
		for (int i=0;i<a[x].size();++i)
		{
			int y = a[x][i].first;
			int v = a[x][i].second;
			if (v < dis[y]) {
				dis[y] = v;
				q.push({-dis[y], y});
			}	
		} 
	}
	cout << res << endl;
	return ;
}

int main(void)
{
	n = read(), m = read();
	for (int i=1;i<=m;++i)
	{
		int x = read(), y = read(), v = read();
		a[x].push_back({y, v});
		a[y].push_back({x, v});
	}
	Prim();
	return 0;
}
2.3 Kruscal算法
#include <bits/stdc++.h>

using namespace std;
const int N = 3e5;

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

int n, m, res = 0;
int fa[N];
struct node {
	int x, y, v;
	friend bool operator < (node p1, node p2) {
		return p1.v < p2.v;
	}
} e[N];

int get(int x) {
	if (fa[x] == x) return x;
	return fa[x] = get(fa[x]);
}

int main(void)
{
	n = read(), m = read();
	for (int i=1;i<=m;++i)
	{
		int x = read(), y = read(), v = read();
		e[i] = {x, y, v};
	}
	for (int i=1;i<=n;++i) fa[i] = i;
	sort(e+1, e+m+1);
	for (int i=1;i<=m;++i)
	{
		int x = e[i].x, y = e[i].y;
		if (get(x) == get(y)) continue;
		res += e[i].v;
		fa[get(x)] = get(y);
	}
	cout << res << endl;
	return 0;
}

3 差分约束系统

  • 求解差分约束问题的最大值:形式为x−y≤kx-y\le kxyk,则(y,x,k)(y,x,k)(y,x,k)连边跑最短路。
  • 求解差分约束问题的最小值:形式为x−y≥kx-y\ge kxyk,则(y,x,k)(y,x,k)(y,x,k)连边跑最长路。
#include <bits/stdc++.h>

using namespace std;
const int N = 3e5;

int n, m;
int vis[N], dis[N], cnt[N];
vector < pair < int, int > > a[N];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

void SPFA(void)
{
	queue < int > q;
	memset(vis, 0, sizeof vis);
	memset(dis, 30, sizeof dis);
	q.push(dis[0] = 0), vis[0] = 1;
	while (q.size())
	{
		int x = q.front(); q.pop();
		vis[x] = 0;
		if (++ cnt[x] > 100) { puts("NO"); exit(0); }
		for (int i=0;i<a[x].size();++i)
		{
			int y = a[x][i].first;
			int v = a[x][i].second;
			if (dis[x] + v < dis[y]) {
				dis[y] = dis[x] + v;
				if (vis[y] == 0) q.push(y), vis[y] = 1;
			}
		}
	}
	for (int i=1;i<=n;++i) printf("%d\n", dis[i]);
	return;
}

int main(void)
{
	n = read(), m = read();
	for (int i=1;i<=m;++i)
	{
		int x = read(), y = read(), v = read();
		a[y].push_back({x, v});
	}
	for (int i=1;i<=n;++i) a[0].push_back({i, 0});
	SPFA();
	return 0;
}

4 ST表

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5;

int n, m;
int a[N], f[N][30];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

int main(void)
{
	n = read(), m = read();
	for (int i=1;i<=n;++i) {
		a[i] = read();
		f[i][0] = a[i];
	}
	for (int j=1;j<=log2(n);++j)
		for (int i=1;i<=n-(1<<j)+1;++i)
			f[i][j] = max(f[i][j-1], f[i+(1<<j-1)][j-1]);
	while (m --)
	{
		int l = read(), r = read();
		int k = log2(r - l + 1);
		printf("%d\n", max(f[l][k], f[r-(1<<k)+1][k]));
	}
	return 0;
}

5 莫队

#include <bits/stdc++.h>

using namespace std;
const int N = 2e6;

int n, T, m, ans;
int c[N], cnt[N], res[N];
struct node {
	int l, r, bel, id;
	friend bool operator < (node p1, node p2) {
		if (p1.bel == p2.bel) return p1.r < p2.r;
		return p1.bel < p2.bel;
	}
} a[N];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

void add(int x)
{
	cnt[c[x]] ++;
	if (cnt[c[x]] == 1) ans ++;
}

void del(int x)
{
	cnt[c[x]] --;
	if (cnt[c[x]] == 0) ans --;
}

int main(void)
{
	T = sqrt(n = read());
	for (int i=1;i<=n;++i) c[i] = read();
	m = read();
	for (int i=1;i<=m;++i)
	{
		a[i].l = read();
		a[i].r = read();
		a[i].bel = (a[i].l - 1) / T;
		a[i].id = i;
	}
	sort(a+1, a+m+1);
	int l = 1, r = 0;
	for (int i=1;i<=m;++i)
	{
		while (l > a[i].l) add(-- l);
		while (r < a[i].r) add(++ r);
		while (l < a[i].l) del(l ++);
		while (r > a[i].r) del(r --);
		res[a[i].id] = ans;
	}
	for (int i=1;i<=m;++i) printf("%d\n", res[i]);
	return 0;
}


6 Dsu on Tree

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 5e5;

int n, Max;
long long sum = 0;
int siz[N], son[N], cnt[N], res[N], c[N];
vector < int > a[N];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

void Dfs(int x, int fa)
{
	siz[x] = 1;
	for (int i=0;i<a[x].size();++i)
	{
		int y = a[x][i];
		if (y == fa) continue;
		Dfs(y, x);
		siz[x] += siz[y];
		if (siz[y] > siz[son[x]]) son[x] = y;
	}
	return;
}

void Modify(int x, int fa, int add, int Son)
{
	cnt[c[x]] += add;
	if (cnt[c[x]] > Max) Max = cnt[sum = c[x]];
	else if (cnt[c[x]] == Max) sum += c[x];
	for (int i=0;i<a[x].size();++i)
	{
		int y = a[x][i];
		if (y == fa || y == Son) continue;
		Modify(y, x, add, 0); 
	}
	return;
}

void Dsu(int x, int fa, int flag)
{
	for (int i=0;i<a[x].size();++i)
	{
		int y = a[x][i];
		if (y == fa || y == son[x]) continue;
		Dsu(y, x, 0);
	}
	if (son[x]) Dsu(son[x], x, 1);
	Modify(x, fa, 1, son[x]);
	res[x] = sum;
	if (flag == 0) Modify(x, fa, -1, 0), sum = Max = 0;
	return;
}

signed main(void)
{
	n = read();
	for (int i=1;i<=n;++i) c[i] = read();
	for (int i=1;i<n;++i)
	{
		int x = read(), y = read();
		a[x].push_back(y);
		a[y].push_back(x);
	}
	Dfs(1, 0);
	Dsu(1, 0, 1);
	for (int i=1;i<=n;++i) printf("%lld ", res[i]);
	return 0;
}

7 线性筛

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5;

int n, k, cnt;
int prime[50000000], vis[100000010];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

int main(void)
{
	n = read(), k = read();
	for (int i=2;i<=n;++i)
	{
		if (vis[i] == 0) prime[++ cnt] = i;
		for (int j=1;j<=cnt&&i*prime[j]<=n;++j)
		{
			vis[i*prime[j]] = 1;
			if (i % prime[j] == 0) break;
		} 
	}
	while (k --) printf("%d\n", prime[read()]);
	return 0;
}

8 欧拉函数

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5;

int n, k, cnt;
int prime[50000000], vis[100000010], phi[100000];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (!isdigit(c)) w |= c == '-', c = getchar();
	while (isdigit(c)) s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

int main(void)
{
	n = read(), k = read();
	for (int i=2;i<=n;++i)
	{
		if (vis[i] == 0) prime[++ cnt] = i, phi[i] = i - 1;
		for (int j=1;j<=cnt&&i*prime[j]<=n;++j)
		{
			vis[i*prime[j]] = 1;
			if (i % prime[j] == 0) { phi[i*prime[j]] = phi[i] * prime[j]; break; }
			if (i % prime[j] != 0) phi[i * prime[j]] = phi[i] * (prime[j] - 1);
		} 
	}
	for (int i=1;i<=30;++i) cout << i << ':' << phi[i] << endl;
	return 0;
}

9 线性求逆元

#include <bits/stdc++.h>

using namespace std;
const int N = 5e6;

int n, P;
int inv[N];

int main(void)
{
	cin >> n >> P;
	inv[1] = 1;
	for (int i=2;i<=n;++i)
		inv[i] = 1LL * (P - P / i) * inv[P % i] % P;
	for (int i=1;i<=n;++i) printf("%d\n", inv[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值