kruskal + lca,90pts求调
查看原帖
kruskal + lca,90pts求调
481621
Zhang_Wenjie楼主2024/4/10 13:30

思路是先求一个最大生成树,两点之间用 lca 维护唯一路径并记录最小值。qwq

#include <bits/stdc++.h>
#define re register int 
#define min(x, y) (x < y ? x : y)
using namespace std;
const int N = 1e5 + 10, M = 3e5 + 10, logN = 50, inf = 1e6;
struct Edge
{
	int to, w, next;
}e[M];
int top, h[N], dep[N], fa[N][logN], w[N][logN];
struct edge
{
	int x, y, w;
}g[M];
int idx, f[N];
int n, m, q, ans = inf;
bool vis[N];
bool cmp(edge i, edge j) { return i.w > j.w; }

inline void add(int x, int y, int w)
{
	e[++ top] = {y, w, h[x]};
	h[x] = top;
}

int find(int x)
{
	return f[x] == x ? x : f[x] = find(f[x]);
}

inline void kruskal()
{
	for (re i = 1; i <= n; i ++) f[i] = i;
	sort(g + 1, g + idx + 1, cmp);
	
	for (re i = 1; i <= idx; i ++)
	{
		int x = g[i].x, y = g[i].y, w = g[i].w;
		if (find(x) != find(y))
		{
			f[find(x)] = find(y);
			add(x, y, w);
			add(y, x, w);
		}
	}
	return;
}

void dfs(int u)
{	
	vis[u] = true;
	for (re i = h[u]; i; i = e[i].next)
	{
		int v = e[i].to;
		if (!vis[v]) // u <- v
		{
			dep[v] = dep[u] + 1;
			fa[v][0] = u;
			w[v][0] = e[i].w;
//			cout << v << ' ' << w[v][0] << "ikun\n";
			dfs(v);
		}
	}
	return;
}

inline void init()
{
	memset(w, inf, sizeof(w)); 
	for (re i = 1; i <= n; i ++)
		if (!vis[i])
		{
			dep[i] = 1;
			dfs(i);
		}
	for (re i = 1; i <= log(n); i ++)
		for (re u = 1; u <= n; u ++)
		{
			fa[u][i] = fa[fa[u][i - 1]][i - 1];
			w[u][i] = min(w[u][i - 1], w[fa[u][i - 1]][i - 1]);
		}	
	return;	
}

inline int lca(int u, int v)
{
	ans = inf;
	if (dep[u] < dep[v]) swap(u, v);
	
	for (re i = log2(n); i >= 0; i --)
		if (dep[fa[u][i]] >= dep[v]) 
		{
			ans = min(ans, w[u][i]);
			u = fa[u][i];	
		}
	if (u == v) return ans;
	
	for (re i = log2(n); i >= 0; i --)
		if (fa[u][i] != fa[v][i])
		{
			ans = min(ans, min(w[u][i], w[v][i]));
			u = fa[u][i], v = fa[v][i];
		}
	return ans = min(ans, min(w[u][0], w[v][0]));
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	cin >> n >> m >> q;
	for (re i = 1; i <= m; i ++)
	{
		int x, y, z; cin >> x >> y >> z;
		g[++ idx] = {x, y, z};
	}
	kruskal();

	init();
	while (q --)
	{
		int x, y; cin >> x >> y;
		if (find(x) != find(y)) cout << "-1\n";
		else
			cout << lca(x, y) << '\n';
	}
	
	return 0;
}
2024/4/10 13:30
加载中...