传送门
Solution:
一辆车的载重,取决于他到终点上的路的载重最小值,最小值越大,装的就越多
考虑如何找路径,如果bfs或者dfs的话,TLE。
这时想到,我们可以做一颗最大生成树(按照权值从大到小排序),在生成树的基础上,两点之间都是联通的,而且载重也是最优的。
这时考虑如何在生成树上找到两点的路径,一棵树,自然而然地就想到了LCA,然后就AC了。
#include
#define N 10005
#define M 50005
using namespace std;
int n,m,father[N],tot,first[N],dep[N],up[N][22],w[N][22];
const int INF=0x7fffffff;
struct A
{
int from,to,val;
}a[M];
struct node
{
int to,next,val;
}edge[2*M];
inline int getfather(int x)
{
if(father[x]==x) return x;
father[x]=getfather(father[x]);
return father[x];
}
inline void addedge(int x,int y,int z)
{
tot++;
edge[tot].to=y;
edge[tot].next=first[x];
edge[tot].val=z;
first[x]=tot;
}
inline bool cmp(const A &x,const A &y)
{
return x.val>y.val;
}
void Init()
{
for(int i=1;i<=n;i++)
{
father[i]=i;
}
}
void kruskal()
{
int k=0;
for(int i=1;i<=m;i++)
{
int x=a[i].from;
int y=a[i].to;
int ax=getfather(x);
int bx=getfather(y);
if(ax!=bx)
{
father[ax]=bx;
k++;
addedge(x,y,a[i].val);
addedge(y,x,a[i].val);
}
if(k==n-1) break;
}
}
inline void dfs(int now)
{
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
if(dep[vis]) continue;
dep[vis]=dep[now]+1;
up[vis][0]=now;
w[vis][0]=edge[u].val;
dfs(vis);
}
}
inline int lca(int x,int y)
{
if(getfather(x)!=getfather(y)) return -1;
if(dep[x]=0;i--)//注意是到0,而不是1,是1就WA了
{
if(dep[up[x][i]]>=dep[y])
{
ans=min(ans,w[x][i]);
x=up[x][i];
}
}
if(x==y) return ans;
for(int i=20;i>=0;i--)
{
if(up[x][i]!=up[y][i])
{
ans=min(ans,min(w[x][i],w[y][i]));
x=up[x][i];
y=up[y][i];
}
}
ans=min(ans,min(w[x][0],w[y][0]));
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin>>n>>m;
Init();
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
a[i].from=x,a[i].to=y,a[i].val=z;
}
sort(a+1,a+m+1,cmp);
kruskal();
for(int i=1;i<=n;i++)//由于不确定生成树包含哪些点 所以要一个一个扫描
{
if(!dep[i])
{
dep[i]=1;
dfs(i);
up[i][0]=i;
w[i][0]=INF;
}
}
for(int j=1;j<=20;j++)
{
for(int i=1;i<=n;i++)
{
up[i][j]=up[up[i][j-1]][j-1];
w[i][j]=min(w[i][j-1],w[up[i][j-1]][j-1]);
}
}
int q;
cin>>q;
for(int i=1;i<=q;i++)
{
int x,y;
cin>>x>>y;
cout<