问题 B: 小Y的图
题目描述
小Y有一个n个点的无向图,图中的每个点从1到n标号。图中还有m条边,每条边有一个长度。
小Y有Q个询问,每次询问两个点所有路径中,最长的边最小值是多少,若这两个点之间没有任何路径,输出 -1。
输入
第一行三个整数n、m和Q。
接下来m行每行三个整数x、y、z(1≤x,y≤n,1≤z≤1000000),表示有一条连接x和y长度为z的边。
接下来Q行每行两个整数x、y(x≤y),表示一组询问。
输出
Q行每行一个整数,表示一组询问的答案。
样例输入 Copy
5 5 4 1 2 3 1 3 2 3 2 1 1 4 5 2 4 4 1 2 1 4 3 5 2 4
样例输出 Copy
2 4 -1 4
题目大意:
中文题意
题目思路:
其实之前,一直想找一个这种题..
刚好这题长我思路上了..
首先,最关键的就是题目中的最长的边的最小值
考虑最长边的最小值,那么最小生成树就出现了
可以想到把图全部退化最小生成树之后,任意两点之间的路径的最大值都是最优的
可以瞎证明一下:假设当前边(u,v)增加之后,使得u,v联通,那么如果不是最小生成树边,说明该边权比最小生成树上的边大,那么路径上的最大值就会增大
所以我们可以把图退化为最小生成树
之后就是询问树上任意两点的最大值
这个询问的话,就比较好处理了,点分治、整体二分、倍增都可以解决
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int Maxn=2e7+10;
const int maxn =3e5+10;
const int mod=1e9+9;
const int Mod = 1e9+7;
///const double eps=1e-10;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
vector< pair<int,int> >v[maxn];
int pre[maxn];
int f[maxn][20],Max[maxn][20];
int vis[maxn];
int Find(int x){
return pre[x] == x?x:pre[x] = Find(pre[x]);
}
struct Edge{
ll x,y,w;
}q[maxn];
bool cmp(Edge a,Edge b){
return a.w < b.w;
}
int deep[maxn];
void dfs(int u,int fa,ll w)
{
deep[u] = deep[fa]+1;
f[u][0] = fa;
Max[u][0] = w;
for(int k=1;k<=19;k++) f[u][k] = f[f[u][k-1]][k-1];
for(int k=1;k<=19;k++) Max[u][k] = max(Max[u][k-1],Max[f[u][k-1]][k-1]);
for(auto x:v[u]){
if(x.first == fa) continue;
dfs(x.first,u,x.second);
}
}
ll LCA(int u,int v)
{
ll res = 0;
if(deep[u]<deep[v]) swap(u,v);//保持u比v深
for(int i=19;i>=0;i--){
if(deep[f[u][i]]>=deep[v]){
res = max(res,Max[u][i]*1ll);
u=f[u][i];
}
}
if(u==v) return res;
for(int i=19;i>=0;i--){
if(f[u][i]!=f[v][i]){
res = max(res,Max[u][i]*1ll);
res = max(res,Max[v][i]*1ll);
u=f[u][i];
v=f[v][i];
}
}
return max(res,max(Max[u][0],Max[v][0])*1ll);
}
int main()
{
read(n);read(m);read(p);
for(int i=1;i<=n;i++) pre[i] = i;
for(int i=1;i<=m;i++){
read(q[i].x);
read(q[i].y);
read(q[i].w);
}
sort(q+1,q+1+m,cmp);
for(int i=1;i<=m;i++){
int dx = Find(q[i].x),dy = Find(q[i].y);
if(dx != dy){
v[q[i].x].push_back({q[i].y,q[i].w});
v[q[i].y].push_back({q[i].x,q[i].w});
pre[dx] = dy;
}
}
for(int i=1;i<=n;i++){
if(!deep[i])
dfs(i,i,-1);
}
for(int i=1;i<=p;i++){
ll x,y;read(x);read(y);
if(Find(x)!=Find(y)) printf("-1\n");
else printf("%lld\n",LCA(x,y));
}
return 0;
}
/**
1 1 5
1 2 4
1 3 3
2 2 3
**/