题目描述
AA 国有 nn 座城市,编号从 11 到 nn ,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入输出格式
输入格式:第一行有两个用一个空格隔开的整数 n,mn,m ,表示 AA 国有 nn 座城市和 mm 条道路。
接下来 mm 行每行 33 个整数 x, y, zx,y,z ,每两个整数之间用一个空格隔开,表示从 xx 号城市到 yy 号城市有一条限重为 zz的道路。注意: xx 不等于 yy ,两座城市之间可能有多条道路 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。
输出格式:共有 qq 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出 -1−1 。
输入输出样例
说明
对于 30\%30% 的数据, 0 < n < 1,000,0 < m < 10,000,0 < q< 1,0000<n<1,000,0<m<10,000,0<q<1,000 ;
对于 60\%60% 的数据, 0 < n < 1,000,0 < m < 50,000,0 < q< 1,0000<n<1,000,0<m<50,000,0<q<1,000 ;
对于 100\%100% 的数据, 0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,0000<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,000 。
#include <bits/stdc++.h>
using namespace std;
int n, m;
const int maxn = 10010;
const int maxm = 50010;
const int inf = 0x3f3f3f3f;
struct node
{
int x,y,z;
}l[maxm];
int cnt = 0;
int to[maxm], cost[maxm], fr[maxm], edge[maxn];
void add(int x, int y, int z) // 邻接表
{
to[cnt] = y;
cost[cnt] = z;
fr[cnt] = edge[x];
edge[x] = cnt;
cnt++;
}
int par[maxn],ran[maxn];
int Find(int x)
{
if (par[x] == x)
return x;
else
return par[x] = Find(par[x]);
}
void unite(int x, int y)
{
x = Find(x);
y = Find(y);
if (x == y)
return;
if (ran[x] < ran[y]) // 路径压缩
par[x] = y;
else
{
par[y] = x;
if (ran[x] == ran[y])
ran[x]++;
}
}
bool cmp(const node& a, const node& b) {return a.z > b.z;}
void kruskal()
{
sort(l + 1, l + m + 1, cmp);
memset(edge, -1, sizeof edge);
for (int i = 1; i <= n; i++) // 并查集初始化
{
par[i] = i;
ran[i] = 0;
}
for (int i = 1; i <= m; i++) // 并查集
{
if(Find(l[i].x) != Find(l[i].y))
{
unite(l[i].x, l[i].y);
add(l[i].x, l[i].y, l[i].z);
add(l[i].y, l[i].x, l[i].z);
}
}
}
bool vis[maxn];
int dep[maxn], f[maxn][21], w[maxn][21];
void dfs(int id, int deep, int fa, int dis)
{
vis[id] = 1;
dep[id] = deep;
f[id][0] = fa;
w[id][0] = dis;
for (int i = edge[id]; i != -1; i = fr[i])
{
if (vis[to[i]])
continue;
dfs(to[i], deep + 1, id, cost[i]);
}
return ;
}
int lca(int x, int y)
{
if (Find(x) != Find(y)) // 不连通
return -1;
int ans = inf;
if(dep[x] > dep[y]) // y 较深
swap(x, y);
for (int j = 20; j >= 0; j--)
{
if (dep[f[y][j]] >= dep[x])
{
ans = min(ans, w[y][j]);
y = f[y][j];
}
}
if (x == y)
return ans;
for (int j = 20; j >= 0; j--)
{
if (f[x][j] != f[y][j])
{
ans = min(ans, min(w[x][j],w[y][j]));
x = f[x][j];
y = f[y][j];
}
}
ans = min(ans,min(w[x][0], w[y][0]));
return ans;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) // 保存原图
{
scanf("%d%d%d", &l[i].x, &l[i].y, &l[i].z);
}
kruskal(); // 最大生成树
for (int i = 1; i <= n; i++)
{
if (!vis[i])
dfs(i, 1, 0, inf);
}
for (int j = 1; j <= 20; j++) // 倍增打表
{
for (int i = 1; i <= n; i++)
{
f[i][j] = f[f[i][j - 1]][j - 1];
w[i][j] = min(w[i][j - 1], w[f[i][j - 1]][j - 1]);
}
}
int q;
scanf("%d", &q);
while (q--)
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", lca(a, b));
}
return 0;
}