题面:Luogu1967
乍一看,网络流水题?
不存在的,有多组询问+起始点和终止点各不相同。。。
那不能用网络流还能用什么?
我们可以发现,题目所要求的那条路径一定在当前连通块的最大生成树上
这是一定的,否则找不到更大的一条路径里边的最小值比这条更大
所以就很容易想到Kruskal求出最大生成森林(图不一定连通)之后在树上进行操作了
具体什么操作呢?就是找两点间在树上路径的最小值即可
如果两点属于不同生成树,输出-1
看其他网上题解都是啥倍增一下或者找LCA之类的东西
我呢直接大力树剖,当然啦调了半个小时QAQ
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<string>
#include<ctime>
#include<map>
#include<climits>
#include<set>
using namespace std;
struct ppap{int x,y,v;}a[100001];
inline bool cmp(ppap a,ppap b){return a.v>b.v;}
int nedge=0,p[200001],c[200001],nex[200001],head[200001];
int n,m,gfa[100001],fa[100001],deep[100001],s[100001],son[100001],top[100001],jzq[400001];
int sum=0,xs[400001],sx[400001],lt[400001],rt[400001],t[400001];
inline void addedge(int x,int y,int z){
p[++nedge]=y;c[nedge]=z;nex[nedge]=head[x];head[x]=nedge;
}
inline int getfather(int v){return gfa[v]==v?v:gfa[v]=getfather(gfa[v]);}
inline void dfs(int x,int Fa,int dep){
fa[x]=Fa;deep[x]=dep;s[x]=1;
for(int k=head[x];k;k=nex[k])if(p[k]!=Fa){
dfs(p[k],x,dep+1);s[x]+=s[p[k]];
if(!son[x]||s[p[k]]>s[son[x]])son[x]=p[k];
}
}
inline void dfss(int x,int g,int qz){
top[x]=g;sx[x]=++sum;xs[sum]=x;jzq[x]=qz;
if(!son[x])return;
for(int k=head[x];k;k=nex[k])if(p[k]==son[x]){dfss(son[x],g,c[k]);break;}
for(int k=head[x];k;k=nex[k])if(p[k]!=fa[x]&&p[k]!=son[x])dfss(p[k],p[k],c[k]);
}
inline void build(int l,int r,int nod){
lt[nod]=l;rt[nod]=r;
if(l==r){t[nod]=jzq[xs[l]];return;}
int mid=l+r>>1;
build(l,mid,nod*2);build(mid+1,r,nod*2+1);
t[nod]=min(t[nod*2],t[nod*2+1]);
}
inline int ssum(int i,int j,int nod){
if(lt[nod]>=i&&rt[nod]<=j)return t[nod];
int mid=lt[nod]+rt[nod]>>1,ans=1e9;
if(i<=mid)ans=min(ans,ssum(i,j,nod*2));
if(j>mid)ans=min(ans,ssum(i,j,nod*2+1));
return ans;
}
inline int fsum(int x,int y){
int fx=top[x],fy=top[y],ans=1e9;
while(fx!=fy){
if(deep[fx]<deep[fy])swap(fx,fy),swap(x,y);
ans=min(ans,ssum(sx[fx],sx[x],1));
x=fa[fx];fx=top[x];
}
if(deep[x]>deep[y])swap(x,y);
ans=min(ans,ssum(sx[x]+1,sx[y],1));
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);
sort(a+1,a+m+1,cmp);
for(int i=1;i<=n;i++)gfa[i]=i;
int cnt=0;
for(int i=1;i<=m;i++){
int fx=getfather(a[i].x),fy=getfather(a[i].y);
if(fx==fy)continue;cnt++;
gfa[fx]=fy;addedge(a[i].x,a[i].y,a[i].v);addedge(a[i].y,a[i].x,a[i].v);
if(cnt==n-1)break;
}//以上Kruskal求最大生成树
for(int i=1;i<=n;i++)if(!deep[i])dfs(i,0,1),dfss(i,0,0);//从这里开始树剖
build(1,n,1);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
int fx=getfather(x),fy=getfather(y);
if(fx!=fy)puts("-1");//判连通
else printf("%d\n",fsum(x,y));
}
return 0;
}