货车运输
P1967 [NOIP2013 提高组] 货车运输 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
- kur+LCA(树上倍增,并查集,最大生成树)
- 对于原来的图如果形成了环,那么环上权值最小的是可以舍去的,由此生成一颗最大生成树(kur)
- f[i][j]代表i的第2j个父节点是谁,w[i][j]代表从第i到第i的第2j个父亲的路程中最小权值是多少,也就是答案(最大承重)
- dfs用于处理每个点的deep,f[i][0],w[i][0]值,用于后面动态规划求出f,w所有的值,(类似于动态规划问题的初始化过程),其中每个根节点的父亲为他本身,权值为无穷大
- LCA初始化就是动态规划过程,即i点的第2j个父亲是i点的第2j-1个父亲的第2j-1个父亲,权值为两者中最小的
- LCA先将深度大的点抬到相同的高度,再两个点同时向根节点推进,知道它们的父亲刚好是同一个点,在推进的过程不断更新最小权值也就是答案
// 4 3
// 1 2 4
// 2 3 3
// 3 1 1
// 3
// 1 3
// 1 4
// 1 3
// https://www.luogu.com.cn/problem/P1967
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define NMAX 10005
#define EMAX 100005
#define INF 1e9
int n, m, q;
bool vis[NMAX];
struct Node1
{
int u, v, w;
} edge_k[EMAX];
int head[NMAX], idx;
struct Node2
{
int to, w, nex;
} edge_[EMAX];
void add(int u, int v, int w)
{
edge_[++idx] = (Node2){v, w, head[u]};
head[u] = idx;
}
bool cmp(Node1 a, Node1 b)
{
return a.w > b.w;
}
void input()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
scanf("%d %d %d", &edge_k[i].u, &edge_k[i].v, &edge_k[i].w);
}
cin >> q;
sort(edge_k + 1, edge_k + 1 + m, cmp);
}
int parent[NMAX];
void init()
{
for (int i = 1; i <= n; i++)
parent[i] = i;
}
int fa(int x)
{
return (x == parent[x]) ? x : parent[x] = fa(parent[x]);
}
void kur()
{
init();
for (int i = 1; i <= m; i++)
{
int fx = fa(edge_k[i].u), fy = fa(edge_k[i].v);
if (fx != fy)
{
parent[fx] = fy;
add(edge_k[i].u, edge_k[i].v, edge_k[i].w);
add(edge_k[i].v, edge_k[i].u, edge_k[i].w);
}
}
}
int f[NMAX][21], w[NMAX][21], deep[NMAX];
void dfs(int now)
{
vis[now] = true;
for (int i = head[now]; i; i = edge_[i].nex)
{
int to = edge_[i].to;
if (!vis[to])
{
f[to][0] = now;
w[to][0] = edge_[i].w;
deep[to] = deep[now] + 1;
vis[to] = true;
dfs(to);
}
}
}
int lca(int x, int y)
{
if (fa(x) != fa(y))
return -1;
if (deep[x] > deep[y])
{
swap(x, y);
}
int ans = INF;
for (int i = 20; i >= 0; i--)
{
if (deep[f[y][i]] >= deep[x])
{
ans = min(ans, w[y][i]);
y = f[y][i];
}
}
if (x == y)
{
return ans;
}
for (int i = 20; i >= 0; i--)
{
if (f[x][i] != f[y][i])
{
ans = min(ans, min(w[x][i], w[y][i]));
x = f[x][i], y = f[y][i];
}
}
return min(ans, min(w[x][0], w[y][0]));
}
int main()
{
input();
kur();
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
deep[i] = 1;
dfs(i);
f[i][0] = i;
w[i][0] = INF;
}
}
for (int i = 1; i <= 20; i++)
{
for (int j = 1; j <= n; j++)
{
f[j][i] = f[f[j][i - 1]][i - 1];
w[j][i] = min(w[j][i - 1], w[f[j][i - 1]][i - 1]);
}
}
for (int i = 1; i <= q; i++)
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", lca(a, b));
}
}