真nm简单。。

算法1:
发现其实所有的经过的边都是最小生成树上面的边,跑出最小生成树在上面求LCA即可。

算法2:
考虑从小到枚举每一个加入的边,直到组成最小生成树,没加一条边就判断所有的询问是否连通。
然后我们发现这个算法有点卡,于是我们可以进行优化:

1、开一个beg,beg前的全部枚举过就不用枚举了。
2、记录每一个点被加入最小生成树的时间,然后询问按照这个时间从小到大排序,每当找到一个询问中有点不在最小生成树里面就可以退出枚举。

然后就可以过了awa

#include<bits/stdc++.h>
using namespace std;
const int M=100005;
const int N=10005;
int n,m,cnt=0,k=0,first[M<<1],nxt[M<<1],fa[N],f[N][25],dis[N][25],dep[N];
struct node{
	int u,v;
	int w;
}a[M<<1],e[M<<1];
int cmp(node A,node B){
	return A.w<B.w;
}
void add(int u,int v,int w){
	e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
	nxt[cnt]=first[u];first[u]=cnt;
}
int find(int x){
	if(x==fa[x]) return x;
	else return fa[x]=find(fa[x]);
}
void unionn(int x,int y){
	fa[x]=y;
}
void kruskal(){
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++){
		int f1=find(a[i].u);
		int f2=find(a[i].v);
		if(f1!=f2){
			unionn(f1,f2);
			add(a[i].u,a[i].v,a[i].w);
			add(a[i].v,a[i].u,a[i].w);
			k++;
		}
		if(k==n-1) break;
	}
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		f[u][i]=f[f[u][i-1]][i-1];
		dis[u][i]=max(dis[f[u][i-1]][i-1],dis[u][i-1]);
	}
		
	for(int i=first[u];i;i=nxt[i]){
		int v=e[i].v;
		if(!dep[v]){
			dep[v]=dep[u]+1;
			f[v][0]=u;
			dis[v][0]=e[i].w;
			dfs(v);
		}
	}
}
int LCA(int a,int b){
	if(dep[a]<dep[b]) swap(a,b);
	int t=dep[a]-dep[b];
	for(int i=0;(1<<i)<=t;i++)
	if(t&(1<<i)) a=f[a][i];
	if(a==b) return a;
	for(int j=19;j>=0;j--){
		if(f[a][j]!=f[b][j])
			a=f[a][j],b=f[b][j];
	}
	return f[a][0];
}
int query(int u,int v){
	int t=dep[u]-dep[v],ans=0;
	for(int i=0;(1<<i)<=t;i++)
		if(t&(1<<i)){
			ans=max(ans,dis[u][i]);
			u=f[u][i];
		}
	return ans;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
	}
	sort(a+1,a+1+m,cmp);
	kruskal();
	dep[1]=1;
	dfs(1);
	int q;
	scanf("%d",&q);
	for(int i=1;i<=q;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		int mid=LCA(u,v);
		printf("%d\n",max(query(u,mid),query(v,mid)));
	}
	return 0;
}

算法1如上

还有算法2:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define orz cout<<"lyakioi!!!!!!!!!!!!!!!!!"<<endl
inline int r(){int s=0,k=1;char c=getchar();while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}while(isdigit(c)){s=s*10+c-'0';c=getchar();}return s*k;}
int n,m,q,fa[1000001],beg,times,b[1000001],used[1000001];
struct node
{
	int from,to,dis;
}a[1000001];
struct ask
{
	int from,to,bh,ans;
}t[1000001];
bool cmp(node x,node y)
{
	return x.dis<y.dis;
}
bool pmc(ask x,ask y)
{
	return max(b[x.from],b[x.to])<max(b[y.from],b[y.to]);
}
bool mcp(ask x,ask y)
{
	return x.bh<y.bh;
}
int father(int x)
{
	if(fa[x]!=x)fa[x]=father(fa[x]);
	return fa[x];
}
int main()
{
	beg=1;
	n=r();m=r();
	memset(b,0x3f,sizeof(b));
	for(int i=1;i<=m;i++)
	{
		a[i].from=r();
		a[i].to=r();
		a[i].dis=r();
	}
	q=r();
	for(int i=1;i<=q;i++)
	{
		t[i].from=r();
		t[i].to=r();
		t[i].bh=i;
	}
	sort(a+1,a+m+1,cmp);
	
	for(int i=1;i<=m;i++)
	{
		int x=a[i].from,y=a[i].to;
		if((b[x]>1e9)||(b[y]>1e9))
		{
			times++;
			b[x]=min(b[x],times);
			b[y]=min(b[y],times);
		}
	}
	
	sort(t+1,t+q+1,pmc);
//	for(int i=1;i<=)
	
	
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		int x=a[i].from,y=a[i].to;
		used[x]=used[y]=1;
		int fax=father(x),fay=father(y);
		if(fax!=fay)
		{
			fa[fax]=fay;
			for(int j=beg;j<=q;j++)
			{
				if(t[j].ans)continue;
				x=t[j].from,y=t[j].to;
				
				if(!used[x]||!used[y])break;
				
				fax=father(x),fay=father(y);
				if(fax==fay)t[j].ans=a[i].dis;
				while(t[beg].ans)beg++;
			}
		}
	}
	sort(t+1,t+q+1,mcp);
	for(int i=1;i<=q;i++)cout<<t[i].ans<<endl;
}