Prim+倍增LCA 10pts 求助
查看原帖
Prim+倍增LCA 10pts 求助
309811
一只小H楼主2023/9/9 22:14
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 50010;

struct Node {
	int id, dis, from;
};

struct Edge {
	int nxt;
	int to;
	int w;
	bool vis;
} edge[MAXN * 2];
priority_queue<Node> q;
int head[MAXN], cnt;
int N, M, Q;
int minn[MAXN][15];
int fa[MAXN][15], dep[MAXN];

namespace Prim
{
	int vis[MAXN];

}// namespace Prim

namespace LCA
{
	int vis[MAXN];
}// namespace LCA

bool operator<(const Node& a, const Node& b)
{
	return a.dis < b.dis;
}

void link(int u, int v, int w)
{
	edge[++cnt].nxt = head[u];
	edge[cnt].to = v;
	edge[cnt].w = w;
	head[u] = cnt;
}

void prim()
{
	for (int i = 1; i <= N; i++) {
		if (Prim::vis[N]) continue;
		q.push(Node{i, 0, 0});
		while (!q.empty()) {
			Node u = q.top();
			q.pop();
			if (Prim::vis[u.id]) continue;
			Prim::vis[u.id] = 1;
			edge[u.from].vis = 1;
			if (u.from & 1) edge[u.from + 1].vis = 1;
			else
				edge[u.from - 1].vis = 1;
			for (int i = head[u.id]; i; i = edge[i].nxt) {
				int to = edge[i].to;
				int w = edge[i].w;
				int from = i;
				if (Prim::vis[to]) continue;
				q.push(Node{to, w, from});
			}
		}
	}
}

void dfs(int x, int father, int w)
{
	if (LCA::vis[x]) return;
	LCA::vis[x] = 1;
	fa[x][0] = father;
	minn[x][0] = w;
	dep[x] = dep[father] + 1;
	for (int i = 1; (1 << i) <= 14; i++) {
		fa[x][i] = fa[fa[x][i - 1]][i - 1];
		minn[x][i] = min(minn[x][i - 1], minn[minn[x][i - 1]][i - 1]);
	}
	for (int i = head[x]; i; i = edge[i].nxt) {
		int to = edge[i].to;
		int cw = edge[i].w;
		if (to == father) continue;
		if (!edge[i].vis) continue;//必须是最大生成树上有的边
		dfs(to, x, cw);
	}
}

int getlca(int a, int b)
{
	int ans = 0x7fffffff;
	if (dep[a] < dep[b]) swap(a, b);
	for (int i = 14; i >= 0; i--) {
		if (dep[a] - (1 << i) >= dep[b]) {
			ans = min(ans, minn[a][i]);
			a = fa[a][i];
		}
	}
	if (a == b) return ans;
	for (int i = 14; i >= 0; i--) {
		if (fa[a][i] == fa[b][i]) continue;

		ans = min(ans, min(minn[a][i], minn[b][i]));
		a = fa[a][i], b = fa[b][i];
	}
	if (fa[a][0] == 0) return -1;
	return min(ans, min(minn[a][0], minn[b][0]));
}

int main()
{
	freopen("input", "r", stdin);
	freopen("output", "w", stdout);
	cin >> N >> M;
	for (int i = 1; i <= M; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		link(u, v, w);
		link(v, u, w);
	}
	//使用prim求最大生成树
	prim();
	cin >> Q;
	memset(minn, 0x3f, sizeof(minn));
	for (int i = 1; i <= N; i++) {
		dfs(i, 0, 0);
	}
	//倍增LCA
	for (int i = 1; i <= Q; i++) {
		int a, b;
		cin >> a >> b;
		cout << getlca(a, b) << endl;
	}
	return 0;
}

第三个点输入:

10 24
4 7 19038
7 10 7375
7 9 17853
9 8 6341
7 2 16976
10 3 2835
10 4 19285
9 4 29193
3 4 4852
3 8 16597
9 1 4138
9 7 21611
7 4 10586
10 4 7821
10 9 25636
3 9 28425
2 3 17229
4 8 11331
9 2 25053
6 4 929
8 3 1738
10 9 28542
1 2 28343
3 5 13215
9
7 5
2 4
10 2
5 10
7 10
4 3
10 1
10 4
8 4

输出:

13215
29193
28542
13215
21611
28425
28343
28542
16597

答案:

13215
25053
25053
13215
21611
28425
25053
28542
16597
2023/9/9 22:14
加载中...