# [nearest public ancestor] [biggest bottleneck tree] car 51Nod3061

Posted by littledragon on Mon, 14 Feb 2022 07:40:23 +0100

Planet A has n cities, numbered from 1 to N, with m two-way roads between them. Each road has A weight limit for vehicles, referred to as weight limit. Now there are q trucks transporting goods. Xiao Ming wants to know the maximum load of each truck under the condition of not exceeding the vehicle weight limit.

Input

Two integers n,m in the first line indicate that there are n cities and M roads, separated by spaces. Next, there are three integers x, y and Z in each line of line m, indicating that there is a road with weight limit z from city x to city y. Where x ≠ y, there may be multiple roads between the two cities. The next line has an integer q, which indicates that there are q trucks to transport goods. Next, in line q, two integers a and b in each line indicate that a truck needs to transport goods from city a to city b to ensure that a ≠ b.

Output

There are q lines in total, and an integer in each line indicates the maximum load of each truck. If the truck cannot reach the destination, output - 1.

Sample

InputOutput
```4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3```
```3
-1
3```

Meaning: n cities, m two-way roads, each road has a weight limit w, now there are q groups of inquiries, and each group of inquiries outputs the maximum value of the smallest side on all paths from city a to city b.

Analysis: according to the meaning of the topic, first analyze that the maximum load is the maximum value of the smallest side on all paths from city a to city b, that is, the maximum bottleneck road from a to b. this problem is Minimum bottleneck spanning tree As mentioned in, to find the maximum spanning tree of the graph, the tree chain from a to b is the maximum bottleneck path, that is, each group of queries needs to return the maximum value on the tree chain.

The tree chain from point a to point B can be divided into two parts by lca(a, b). One part is from a to lca(a, b), and the other part is from B to lca(a, b). When using tree multiplication to find fa array, one can be maintained at the same time_ Min array_ min[i][j] represents the minimum value on the path of 2^j layers up from point I, similar to the fa array update method_ Min array update formula is_ Min [now] [i] = min (_min [now] [I-1], _min [fa [now] [I-1] [I-1]), get_ After the Min array, consider the process of finding lca. First, let the points with large depth climb to the same depth position. This process can be assisted by_ Min array to get the minimum value on the path, and then when two points climb up at the same time, it can also be used_ Min array gets the minimum value on the path, which benefits from_ Min and fa arrays have similar meanings. Finally, after climbing to the next level of lca, don't forget that there are two edges that haven't been calculated. Just update them manually.

The specific codes are as follows:

```#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#define inf 0x3f3f3f3f
using namespace std;
//The maximum value of the minimum edge of all paths from s to t requires the maximum spanning tree
int head, fa, cnt, n, m, q, dep, f, _min;
struct edge1
{
int to, next, w;
}e1;
struct edge2
{
int u, v, w;
}e2;

void add(int u, int v, int w)
{
e1[++cnt].to = v;
e1[cnt].w = w;
}

void dfs(int now, int pre)
{
dep[now] = dep[pre]+1;
fa[now] = pre;
for(int i = 1; i < 20; i++)
{
fa[now][i] = fa[fa[now][i-1]][i-1];
_min[now][i] = min(_min[now][i-1], _min[fa[now][i-1]][i-1]);
}
for(int i = head[now]; i; i = e1[i].next)
if(e1[i].to != pre)
{
_min[e1[i].to] = e1[i].w;
dfs(e1[i].to, now);
}
}

int lca(int x, int y, int &ans)
{
if(dep[x] < dep[y]) swap(x, y);
for(int i = 19; i >= 0; i--)
if(dep[fa[x][i]] >= dep[y])
{
ans = min(ans, _min[x][i]);
x = fa[x][i];
}
if(x == y) return x;
for(int i = 19; i >= 0; i--)
if(fa[x][i] != fa[y][i])
{
ans = min(ans, min(_min[x][i], _min[y][i]));
x = fa[x][i], y = fa[y][i];
}
ans = min(ans, min(_min[x], _min[y]));
return fa[x];
}

bool cmp(edge2 a, edge2 b)
{
return a.w > b.w;
}

int find(int x)
{
if(f[x] == x) return x;
return f[x] = find(f[x]);
}

signed main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++)
f[i] = i;
for(int i = 1; i <= m; i++)
scanf("%d%d%d", &e2[i].u, &e2[i].v, &e2[i].w);
sort(e2+1, e2+m+1, cmp);
for(int i = 1; i <= m; i++)
{
if(find(e2[i].u) != find(e2[i].v))
{
f[find(e2[i].u)] = find(e2[i].v);
}
}
for(int i = 0; i < 20; i++)
_min[i] = inf;
for(int i = 1; i <= n; i++)//Forest dfs
if(f[i] == i)
{
_min[i] = inf;
dfs(i, 0);
}
cin >> q;
for(int i = 1; i <= q; i++)
{
int x, y;
scanf("%d%d", &x, &y);
if(find(x) != find(y))
puts("-1");
else
{
int ans = inf;
lca(x, y, ans);
printf("%d\n", ans);
}
}
return 0;
}
```

Topics: Algorithm Graph Theory