UVA11354 Bond
UVA11354 Bond
题目描述
Once again, James Bond is on his way to saving the world. Bond’s latest mission requires him to travel
between several pairs of cities in a certain country.
The country has N cities (numbered by 1, 2, . . . , N), connected by M bidirectional roads. Bond is
going to steal a vehicle, and drive along the roads from city s to city t. The country’s police will be
patrolling the roads, looking for Bond, however, not all roads get the same degree of attention from the
police.
More formally, for each road MI6 has estimated its dangerousness, the higher it is, the more likely
Bond is going to be caught while driving on this road. Dangerousness of a path from s to t is defined
as the maximum dangerousness of any road on this path.
Now, it’s your job to help Bond succeed in saving the world by finding the least dangerous paths
for his mission.
Input
There will be at most 5 cases in the input file.
The first line of each case contains two integers N, M (2 ≤ N ≤ 50000, 1 ≤ M ≤ 100000) – number
of cities and roads. The next M lines describe the roads. The i-th of these lines contains three integers:
xi, yi, di (1 ≤ xi, yi ≤ N, 0 ≤ di ≤ 109) – the numbers of the cities connected by the i-th road and its
dangerousness.
Description of the roads is followed by a line containing an integer Q (1 ≤ Q ≤ 50000), followed by
Q lines, the i-th of which contains two integers si and ti (1 ≤ si, ti ≤ N, si ̸= ti).
Consecutive input sets are separated by a blank line.
Output
For each case, output Q lines, the i-th of which contains the minimum dangerousness of a path between
cities si and ti.
Consecutive output blocks are separated by a blank line.
The input file will be such that there will always be at least one valid path.
Sample Input
4 5
1 2 10
1 3 20
1 4 100
2 4 30
3 4 10
2
1 4
4 1
2 1
1 2 100
1
1 2
Sample Output
20
20
100
================================================================
哇!英文题!
================================================================
翻译:
sideman 做好了回到Gliese 星球的硬件准备,但是 sideman 的导航系统还没有完全设计好。为了方便起见,我们可以认为宇宙是一张有 N 个顶点和 M 条边的带权无向图,顶点表示各个星系,两个星系之间有边就表示两个星系之间可以直航,而边权则是航行的危险程度。
sideman 现在想把危险程度降到最小,具体地来说,就是对于若干个询问 (A, B),sideman 想知道从顶点 A 航行到顶点 B 所经过的最危险的边的危险程度值最小可能是多少。作为sideman 的同学,你们要帮助 sideman 返回家园,兼享受安全美妙的宇宙航行。所以这个任务就交给你了。
抱歉放错翻译了,
那么我们就凑活着用吧
这俩代码就差了个多测
还有这个题 P1967 货车运输 , 三倍经验
======================== 正片开始 ==========================
这个题看起来是最短路
但事实上,一条路径的值,至于路径的最大值有关,而我们需要让这个最大值尽量的小
就是把边权最小的边保留下来即可,最后变成一棵树保证联通,且只有一条路径,然后询问的时候就可以用 log(n) 的 lca 了
lca 时,我们不光要存一个 f [ i ] [ j ] 来表示 i 这个点,跳 2 的 j 次方的距离跳到的祖先节点
还要整一个 d [ i ] [ j ] 表示 i 这个点 ,跳 2 的 j 次方的距离时,经过的最大边权,即为答案
此题有坑
输出格式问题见讨论区
========================
对了,预处理 d 数组时要先预处理完 f 数组;
lca 保存路径的最大值是要先保存,再往上跳;
道理大家都懂,其它见代码
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 3e5 + 5;
const int M = 3e5 + 5;
int n,m,k;
struct stu{
int x,y,z;
}e[N];
int fa[N];
int f[N][20];
int d[N][20];
int dep[N];
int find(int x)
{
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
bool cmp(stu x,stu y)
{
return x.z < y.z;
}
int tot,head[N],to[N << 1],nxt[N << 1],w[N << 1];
void add(int x,int y,int z) {to[++ tot] = y;w[tot] = z;nxt[tot] = head[x];head[x] = tot;}
void dfs(int x,int p)
{
for(int i = 1;i <= 19;i ++) f[x][i] = f[f[x][i - 1]][i - 1];
for(int i = 1;i <= 19;i ++) d[x][i] = max(d[x][i - 1],d[f[x][i - 1]][i - 1]);
for(int i = head[x];i;i = nxt[i])
{
int y = to[i];
if(y == p) continue;
dep[y] = dep[x] + 1;
f[y][0] = x;
d[y][0] = w[i];
dfs(y,x);
}
}
int lca(int a,int b)
{
if(dep[a] < dep[b]) swap(a,b);
int res = 0;
for(int i = 19;i >= 0;i --)
if(dep[f[a][i]] >= dep[b])
res = max(res,d[a][i]),a = f[a][i];
if(a == b) return res;
for(int i = 19;i >= 0;i --)
if(f[a][i] != f[b][i])
{
res = max(res,max(d[a][i],d[b][i]));
a = f[a][i];
b = f[b][i];
//记得先统计,再跳跃
}
res = max(res,max(d[a][0],d[b][0]));
return res;
}
int main()
{
// freopen("1.out","w",stdout);
int T = 0;
while(cin >> n >> m)
{
T ++;
if(T != 1) cout << endl;
//这里可能就是这是紫题的原因
tot = 0;
memset(head,0,sizeof head);
memset(f,0,sizeof f);
memset(d,0,sizeof d);
for(int i = 1;i <= n;i ++) fa[i] = i;
//下面是kruskal求最小生成树
for(int i = 1;i <= m;i ++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
sort(e + 1,e + 1 + m,cmp);
for(int i = 1;i <= m;i ++)
{
int x = find(e[i].x);
int y = find(e[i].y);
if(x == y) continue;
fa[x] = y;
add(e[i].x,e[i].y,e[i].z);
add(e[i].y,e[i].x,e[i].z);
}
dep[1] = 1;
dfs(1,-1);
//这波唤作预处理
cin >> k;
for(int t = 1;t <= k;t ++)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d",lca(x,y));
cout << endl;
}
}
return 0;
}