给出一个
N
≤
1
e
5
,
M
≤
3
e
5
N\leq1e5,M\leq3e5
N≤1e5,M≤3e5的无向图,无向图的图上有边权。然后给出
q
≤
1
e
5
q\leq1e5
q≤1e5次询问,每次询问给出两个点
u
,
v
u,v
u,v,求
u
,
v
u,v
u,v路径上最大边的最小值。
应该是一个挺常规的问题:
容易想到这样的路径是最小生成树上的路径。先求出最小生成树,然后可以预处理出
l
c
a
lca
lca,在倍增的过程中可以维护每个结点向上
2
k
2^{k}
2k级祖先的边权的最大值。
注意可能不连通。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e5+7;
int fa[N];
int find(int x) {
if(fa[x]==x) return fa[x];
else return fa[x]=find(fa[x]);
}
void unity(int x,int y) {
x=find(x);
y=find(y);
if(x==y) return;
fa[x]=y;
}
struct Edge {
int u,v,w;
bool operator <(const Edge &rhs) const {
return w<rhs.w;
}
}e[3*N];
struct edge{ int v,w; };
vector<edge> go[N];
int dep[N];
int f[N][22],mi[N][22];
void dfs(int u,int fa) {
for(auto &e:go[u]) {
int v=e.v,w=e.w;
if(v==fa) continue;
dep[v]=dep[u]+1;
f[v][0]=u;
mi[v][0]=w;
dfs(v,u);
}
}
int lca(int u,int v) {
int ans=0;
if(dep[u]<dep[v]) swap(u,v);
for(int i=20;i>=0;i--) {
if((1<<i)<=dep[u]-dep[v]) {
ans=max(ans,mi[u][i]);
u=f[u][i];
}
}
if(u==v) return ans;
for(int i=20;i>=0;i--) {
if(f[u][i]!=f[v][i]) {
ans=max(ans,mi[u][i]);
ans=max(ans,mi[v][i]);
u=f[u][i],v=f[v][i];
}
}
ans=max(ans,mi[u][0]);
ans=max(ans,mi[v][0]);
return ans;
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[i].u=u;e[i].v=v;e[i].w=w;
}
sort(e+1,e+1+m);
for(int i=1;i<=m;i++) {
int u=e[i].u;
int v=e[i].v;
int w=e[i].w;
int U=find(u);
int V=find(v);
if(U==V) continue;
else {
fa[U]=V;
go[u].push_back({v,w});
go[v].push_back({u,w});
}
}
for(int i=1;i<=n;i++) {
if(!dep[i]) {
dep[i]=1;
dfs(i,0);
}
}
for(int j=1;(1<<j)<=n;j++) {
for(int i=1;i<=n;i++) {
f[i][j]=f[f[i][j-1]][j-1];
mi[i][j]=max(mi[i][j-1],mi[f[i][j-1]][j-1]);
}
}
int q;
scanf("%d",&q);
while(q--) {
int u,v;
scanf("%d%d",&u,&v);
if(find(u)!=find(v)) puts("impossible");
else printf("%d\n",lca(u,v));
}
return 0;
}