https://www.luogu.org/problemnew/show/P1967
A国有n n座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入格式:
第一行有两个用一个空格隔开的整数 n,m 表示 A 国有 n 座城市和 m 条道路。
接下来 m行每行 3 3个整数 x, y, z,每两个整数之间用一个空格隔开,表示从 x号城市到 y号城市有一条限重为 z 的道路。注意: x 不等于 y,两座城市之间可能有多条道路 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。
输出格式:
共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
为了取得最大流量路径,每两个结点之间的路径是一定的,我们只需要找出这条路径便可以得到答案,其多余的路径是无效的,首先跑出原图的最大生成树,用lca处理查询问题。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 10;
const int maxm = 5e4 + 10;
const int INF = 0x3f3f3f3f;
int pre[maxn];
int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); }
struct Krustral
{
int u, v, w;
bool operator<(const Krustral &a) const
{
return w > a.w;
}
} krus[maxm];
vector<pair<int, int>> E[maxn];
int dep[maxn], trefa[maxn][21], wet[maxn][21], vis[maxn];
void dfs(int u)
{
vis[u] = 1;
for (pair<int, int> x : E[u])
{
if (vis[x.first])
continue;
dep[x.first] = dep[u] + 1;
trefa[x.first][0] = u;
wet[x.first][0] = x.second;
dfs(x.first);
}
}
int lca(int x, int y)
{
if (find(x) != find(y))
return -1;
int ans = INF;
if (dep[x] > dep[y])
swap(x, y);
register int i;
for (i = 20; i >= 0; i--)
{
if (dep[trefa[y][i]] >= dep[x]) //使x,y同一深度
{
ans = min(ans, wet[y][i]);
y = trefa[y][i];
}
}
if (x == y)
return ans;
for (i = 20; i >= 0; i--) //两个结点一起向上走
{
if (trefa[x][i] != trefa[y][i])
{
ans = min(ans, min(wet[x][i], wet[y][i]));
x = trefa[x][i];
y = trefa[y][i];
}
}
ans = min(ans, min(wet[x][0], wet[y][0]));
return ans;
}
int main()
{
int n, m, q, x, y, z;
scanf("%d%d", &n, &m);
register int i, j;
for (i = 1; i <= n; i++)
pre[i] = i;
for (i = 0; i < m; i++)
{
scanf("%d%d%d", &x, &y, &z);
krus[i].u = x, krus[i].v = y, krus[i].w = z;
}
sort(krus, krus + m);
int cnt = 0;
for (i = 0; i < m; i++)
{
x = krus[i].u, y = krus[i].v, z = krus[i].w;
if (find(x) != find(y))
{
E[x].emplace_back(make_pair(y, z));
E[y].emplace_back(make_pair(x, z));
pre[find(x)] = find(y);
if (cnt++ == n - 1)
break;
}
}
for (i = 1; i <= n; i++)
{
if (vis[i])
continue;
dep[i] = 1; //根节点初始化
dfs(i);
trefa[i][0] = i;
wet[i][0] = INF;
}
for (i = 1; i <= 20; i++) //初始化
{
for (j = 1; j <= n; j++)
{
trefa[j][i] = trefa[trefa[j][i - 1]][i - 1];
wet[j][i] = min(wet[j][i - 1], wet[trefa[j][i - 1]][i - 1]);
}
}
scanf("%d", &q);
while (q--)
{
scanf("%d%d", &x, &y);
printf("%d\n", lca(x, y));
}
// system("pause");
}