爆零悬棺求救(样例已过,注释在文中)
查看原帖
爆零悬棺求救(样例已过,注释在文中)
1097177
longhaoyuan楼主2024/11/30 20:48

用 kruskal+lca 写的,谁有hack但不想调的直接发过来。
里头有注释:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double dbl;
const int maxn = 1e4+5, maxm = 5e4+5;
typedef array<int, 3> edge; //三元组

int n, m, Q;
edge e[maxm]; //旧图
list<array<int, 2>> g[maxn]; //新图(kruskal后)
int ds[maxn]; //并查集
int dep[maxn], dp[maxn][20], w[maxn][20];
//dep=深度 dp=倍增数组
//w[i][j]=i~(i+2^j)之间最小边权
bool vis[maxn];

int seek(int x){
	return x == ds[x] ? x : ds[x] = seek(ds[x]);
}

void init(int v, int fa, int fw){
  //fa是上一个节点,fw是v与fa之间的边权
	if (~fa) dep[v] = dep[fa]+1;
	dp[v][0] = fa; w[v][0] = fw;
	vis[v] = 1;
	for (int i = 1; i <= 20; i++){
		if (~dp[v][i-1]){
			dp[v][i] = dp[dp[v][i-1]][i-1];
			w[v][i] = min(w[v][i-1], w[dp[v][i-1]][i-1]);
		}else dp[v][i] = -1;
	} //预处理倍增
	for (auto t : g[v]){
		if (t[0] == fa) continue;
		init(t[0], v, t[1]);
	} //继续遍历
}

int lca(int x, int y){
	if (seek(x) != seek(y)) return -1; //特判连通
	int ret = INT_MAX;
	if (dep[x] > dep[y]) swap(x, y);
	for (int i = 20; i >= 0; i--){
		if (dp[y][i] == -1) continue;
		if (dep[dp[y][i]] >= dep[x]){
			ret = min(ret, w[y][i]); y = dp[y][i];
		}
	} //使x与y同深度
	if (x == y) return ret;
	for (int i = 20; i >= 0; i--){
		if (dp[x][i] == -1 || dp[y][i] == -1) continue;
		if (dp[x][i] != dp[y][i]){
			x = dp[x][i]; y = dp[y][i];
			ret = min({ret, w[x][i], w[y][i]});
		}
	} //找到lca,并求x~lca和y~lca中的最小权值
	return ret + w[x][0];
}

int main(){
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++){
		scanf("%d %d %d", &e[i][0], &e[i][1], &e[i][2]);
		e[i][0]--; e[i][1]--;
	}
	
	sort(e, e+m, [](edge l, edge r){return l[2] > r[2];});
	iota(ds, ds+n, 0);
	for (int i = 0; i < m; i++){
		int f1 = seek(e[i][0]), f2 = seek(e[i][1]);
		if (f1 == f2) continue;
		ds[f1] = f2;
		g[e[i][0]].push_back({e[i][1], e[i][2]});
		g[e[i][1]].push_back({e[i][0], e[i][2]});
	} //kruskal
	
	for (int i = 0; i < n; i++) if (!vis[i]) init(i, -1, INT_MAX);
	scanf("%d", &Q); while (Q--){
		int x, y; scanf("%d %d", &x, &y);
		if (x > n || y > n){
			puts("-1");
			continue;
		}
		x--; y--;
		printf("%d\n", lca(x, y));
	}
	return 0;
}
2024/11/30 20:48
加载中...