思路: 其实难点在于如何解决查询的时间复杂度的问题,对于一颗最小生成树,我们可以预先处理出他的anc[][] (倍增父亲)
然后在查询的时候就对于u和v 不断将他们在树上虚拟的向上提,直到提到二者最近公共祖先的直接孩子一级。然后同时记录在“提” 的过程中的最大边。
#include<bits/stdc++.h>
using namespace std;
const int N =5e4+5;
const int M =1e5+5;
const int inf =0x3f3f3f3f;
struct node
{
int u,v,w;
}E[M];
struct Edge
{
int to;
int w;
int next;
//Edge(int t,int _w,int _n):to(t),w(_w),next(_n){}
}edge[2*N];
int tot;
int head[N];
int f[N];
void add(int u,int v,int w)
{
edge[++tot].to=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot;
}
bool cmp(node a,node b)
{
return a.w<b.w;
}
int getf(int x)
{
return f[x]==x?x:(f[x]=getf(f[x]));
}
int merge(int u,int v)
{
int t1=getf(u);
int t2=getf(v);
if(t1!=t2)
{
f[t2]=t1;
return 1;
}
return 0;
}
int Fa;
int cost[N];
int fa[N];
int L[N];
int anc[N][20];
int maxcost[N][20];
int n,m;
void dfs(int u,int ff,int dep)
{
L[u]=dep;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(v==ff) continue;
cost[v]=edge[i].w;
fa[v]=u;
dfs(v,u,dep+1);
}
return ;
}
void pre_init()
{
for(int i=1;i<=n;i++){
anc[i][0]=fa[i]; maxcost[i][0]=cost[i];
for(int j=1;(1<<j)<n;j++){
anc[i][j]=-1;
}
}
for(int j=1;(1<<j)<n;j++){
for(int i=1;i<=n;i++){
if(anc[i][j-1]!=-1){
int a=anc[i][j-1];
anc[i][j]=anc[a][j-1];
maxcost[i][j]=max(maxcost[i][j-1],maxcost[a][j-1]);
}
}
}
}
int query(int p,int q)
{
if(L[p]<L[q]) swap(p,q);
int tmp,log;
for(log=1;(1<<log)<L[p];log++);
log--;
int ans=-inf;
for(int i=log;i>=0;i--){
if(L[p]-(1<<i)>=L[q]){
ans=max(ans,maxcost[p][i]);
p=anc[p][i];
}
}
if(p==q){
return ans;
}
for(int i=log;i>=0;i--){
if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
ans=max(ans,maxcost[p][i]); p=anc[p][i];
ans=max(ans,maxcost[q][i]); q=anc[q][i];
}
}
ans=max(ans,cost[p]);
ans=max(ans,cost[q]);
return ans;
}
void init()
{
memset(L,0,sizeof(L));
memset(cost,0,sizeof(cost));
memset(fa,0,sizeof(fa));
memset(maxcost,0,sizeof(maxcost));
memset(anc,0,sizeof(anc));
}
int main()
{
int ff=0;
while(cin>>n>>m)
{
for(int i=1;i<=m;i++){
scanf("%d %d %d",&E[i].u,&E[i].v,&E[i].w);
}
memset(head,-1,sizeof(head)); tot=0;
sort(E+1,E+m+1,cmp);
int cnt=1;
for(int i=0;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++){
if(merge(E[i].u,E[i].v)){
add(E[i].u,E[i].v,E[i].w);
add(E[i].v,E[i].u,E[i].w);
cnt++;
if(cnt==n) break;
}
}
init();
Fa=1;
dfs(1,-1,0);
pre_init();
int q;
scanf("%d",&q);
int u,v;
if(ff) printf("\n");
while(q--)
{
scanf("%d %d",&u,&v);
printf("%d\n",query(u,v));
}
ff=1;
}
return 0;
}