题目描述
【题意】
有n个点,编号从 1 到 n,有 m 条双向边。每一条边都有权值。现在有 q 个询问,
在x到y的所有路径中,选出一条路径,使得这条路径上面边权的最小值尽量大。
【输入描述】
第一行有两个整数 n,m。
接下来 m 行每行 3 个整数 x、y、z,表示一条权值为z的无向边。
接下来一行有一个整数 q。
接下来 q 行,每行两个整数 x、y(x 不等于 y)。
【输出描述】
输出共有 q 行,每行一个整数,如果该询问的x和y不连通,输出-1。
【样例输入】
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
【样例输出】
3
-1
3
【数据范围及提示】
对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;
对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。
给出一个非常简洁的题目
看到这样的题,如果不是知道听说用树剖来做,我还真的要想很久
因为这一题求的是最小值尽量大,所以还是很容易想到用二分或者生成树的
但是因为有q个询问,二分明显是不行的(你怎么判定这个值是否可以)
所以就只能用生成树了
首先肯定是最大生成树,因为要让边尽量大,而且也不会影响结果(既然树上可以这样走,那图上面也肯定可以这样走)
然而,这并不是一个联通图,所以我们要定义一个root,把生成树以后每一棵树连在一起来查询
记得连向根节点的边权值为正无穷
因为这道题是静态查询,所以我们只需要用lca(常数比树剖小)来查询
参考代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
inline int read() {
int x = 0 ; char s = getchar() ;
while ( !isdigit(s) ) s = getchar() ;
while ( isdigit(s) ) x = (x<<1) + (x<<3) + (s-48) , s = getchar() ;
return x ;
}
const int N = 1e4 + 20 ;
const int M = 5e4 + 20 ;
const int root = 1e4 + 2 ;
struct edge {
int v , w , nxt ;
}e[N<<1] ; int tot , last[N] ;
inline void add ( int u , int v , int w ) {
e[++tot] = (edge){ v , w , last[u] } ;
last[u] = tot ;
e[++tot] = (edge){ u , w , last[v] } ;
last[v] = tot ;
}
struct node {
int x , y , c ;
}a[M] ;
inline bool cmp ( node n1 , node n2 ) {
return n1.c > n2.c ;
}
int fa[N] ;
inline int findfa ( int x ) {
if ( fa[x] == x ) return x ;
return fa[x] = findfa ( fa[x] ) ;
}
int n , m , q ;
int st[N][21] , b[N][21] , dep[N] ;
void dfs ( int u , int fa ) {
st[u][0] = fa ; dep[u] = dep[fa] + 1 ;
for ( int i = 1 ; (1<<i) < dep[u] ; i ++ ) {
st[u][i] = st[st[u][i-1]][i-1] ;
b[u][i] = min ( b[u][i-1] , b[st[u][i-1]][i-1] ) ;
}
for ( int i = last[u] ; i != -1 ; i = e[i].nxt ) {
int v = e[i].v ; if ( v == fa ) continue ;
b[v][0] = e[i].w ; dfs ( v , u ) ;
}
}
int lca ( int x , int y ) {
if ( dep[x] < dep[y] ) swap ( x , y ) ;
int minn = 999999999 ;
for ( int i = 20 ; i >= 0 ; i -- )
if ( dep[x]-dep[y] >= (1<<i) ) {
minn = min ( minn , b[x][i] ) ;
x = st[x][i] ;
}
if ( x == y ) return minn ;
for ( int i = 20 ; i >= 0 ; i -- )
if ( (1<<i) < dep[x] && st[x][i] != st[y][i] ) {
minn = min ( minn , b[x][i] ) ;
minn = min ( minn , b[y][i] ) ;
x = st[x][i] , y = st[y][i] ;
}
if ( st[x][0] == root ) return -1 ;
return min ( minn , min ( b[x][0] , b[y][0] ) ) ;
}
int main() {
n = read() , m = read() ;
for ( int i = 1 ; i <= m ; i ++ )
a[i].x = read() , a[i].y = read() , a[i].c = read() ;
sort ( a + 1 , a + m + 1 , cmp ) ; int s = 0 ;
for ( int i = 1 ; i <= n ; i ++ ) fa[i] = i ;
memset ( last , -1 , sizeof ( last )) , tot = -1 ;
for ( int i = 1 ; i <= m ; i ++ ) {
int fx = findfa ( a[i].x ) ;
int fy = findfa ( a[i].y ) ;
if ( fx == fy ) continue ;
add ( a[i].x , a[i].y , a[i].c ) ; fa[fx] = fy ;
s ++ ; if ( s == n - 1 ) break ;
}
for ( int i = 1 ; i <= n ; i ++ )
if ( fa[i] == i ) add ( root , i , 999999999 ) ;
dfs ( root , 0 ) ; int x , y ; q = read() ;
while ( q -- ) {
x = read() , y = read() ;
printf ( "%d\n" , lca(x,y) ) ;
}
return 0 ;
}