有一个局域网,由 n 个设备和 m 条物理连接组成,第 i 条连接的稳定性为wi 。
对于从设备 A 到设备 B 的一条经过了若干个物理连接的路径,我们记这条路径的稳定性为其经过所有连接中稳定性最低的那个。
我们记设备 A 到设备 B 之间通信的稳定性为 A 至 B 的所有可行路径的稳定性中最高的那一条。
给定局域网中的设备的物理连接情况,求出若干组设备 xi 和 yi 之间的通信稳定性。如果两台设备之间不存在任何路径,请输出 −1 。
输入格式
输入的第一行包含三个整数 n, m, q ,分别表示设备数、物理连接数和询问数。
接下来 m 行,每行包含三个整数 ui , vi ,wi ,分别表示 ui 和 vi 之间有一条稳定性为 wi 的物理连接。
接下来 q 行,每行包含两个整数 xi , yi ,表示查询 xi 和 yi 之间的通信稳定性。
输出格式
输出 q 行,每行包含一个整数依次表示每个询问的答案。
样例输入
复制
5 4 3 1 2 5 2 3 6 3 4 1 1 4 3 1 5 2 4 1 3
样例输出
复制
-1 3 5
解题
最开始我是想用dfs直接写因为他给了起点和终点代码如下
#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#define endl '\n'
#define int long long
using namespace std;
map<int,map<int, int>>arr;
int ans = 0;
int cnt = 0x3f3f3f3f;
int st[50000]={0};
int is[50000] = { 0 };
void dfs(int u, int v,int x)//u为当前的点,u为父节点,v为目标节点
{
if (u == v)
{
ans = max(ans, cnt);
return;
}
for (auto tmp:arr[u])
{
if (st[tmp.first]!=1)
{
st[tmp.first] = 1;
cnt = min(cnt, tmp.second);
dfs(tmp.first, v, u);
}
else
continue;
}
return;
}
void solve()
{
int n, m, s;
cin >> n >> m >> s;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
arr[a][b] = c;
arr[b][a] = c;
is[a] = is[b] = 1;
}
for (int i = 0; i < s; i++)
{
int a, b;
cin >> a >> b;
st[a] = 1;
dfs(a, b, a);
if (st[b]==0||is[b]==0)
cout << -1 << endl;
else
{
cout << ans << endl;
}
ans = 0;
cnt = 0x3f3f3f3f;
memset(st, 0, sizeof(st));
}
}
signed main()
{
ios::sync_with_stdio;
cin.tie(0);
cout.tie(0);
int t = 1;
while (t--)
solve();
return 0;
}
但这样写只得了5分难绷。然后我想到了kruskal 重构树和LCA重新写终于对了下面是正解
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#define int long long
#define endl '\n'
using namespace std;
const int N = 4e5 + 10, K = 20, M = 3e5 + 10;
int par[N], a[N], f[N][K], dep[N], n, m, q,u,v;
bool vis[N];
vector<int>E[N];
struct node
{
int u, v, w;
}e[M];
int find(int x)
{
return par[x] == x ? x :par[x]=find(par[x]);//查找节点x的根节点也就是找到一个节点他的这个连通分量的根节点是他自己
}
bool cmp(node a, node b)
{
return a.w > b.w;
}
void dfs(int u, int fa)
{
vis[u] = true;
dep[u] = dep[fa] + 1;
f[u][0] = fa;
for (auto tmp : E[u])
{
if (tmp!=fa)
dfs(tmp, u);
}
}
int lca(int u, int v)
{
if (dep[u] < dep[v])
swap(u, v);
int d = dep[u] - dep[v];
for (int i = K - 1; i >= 0; i--)
{
if ((d >> i) & 1)
{
u = f[u][i];
}
}//将u,v调整至同一深度
if (u == v)
return u;
for (int i = K - 1; i >= 0; i--)
{
if (f[u][i] != f[v][i])
u = f[u][i], v = f[v][i]; //看上面的每一层节点是否相同,因为是从最高开始看起,所以只要出现这一层两个点的祖先不一样,那这一层的上一层就一定是最近公共祖先
}
return f[u][0];//返回共同节点的父节点
}
void solve()
{
cin >> n >> m>>q;
for (int i = 1; i <= n+m; i++)
par[i] = i;
for (int i = 1; i <= m; i++)
cin >> e[i].u >> e[i].v >> e[i].w;
sort(e + 1, e + m + 1, cmp);
int cnt = n;
for (int i = 1; i <= m; i++)
{
int u = e[i].u;
int v = e[i].v;
int w = e[i].w;
u = find(u), v = find(v);
if (u == v)
continue;
++cnt;
par[u] = par[v] = cnt;
E[cnt].push_back(u);
E[cnt].push_back(v);
a[cnt] = w;
}//捏造一个节点将两个节点连接起来方便find()操作。
for (int i = cnt; i >= 1; i--)
{
if (!vis[i])
dfs(i, 0);//最初将每一个节点的父节点设置为0
}
for (int j = 1; j < K; j++)
for (int i = 1; i <= cnt; i++)
f[i][j] = f[f[i][j - 1]][j - 1];//从底层开始一层一层向上更新
while (q--)
{
cin >> u >> v;
if (find(u) != find(v))
{
cout << -1 << endl;
continue;
}
else
{
cout << a[lca(u,v)] << endl;
}
}
}
signed main()
{
ios::sync_with_stdio;
cin.tie(0);
cout.tie(0);
int t = 1;
while (t--)
solve();
return 0;
}