问题描述
A 国有 n 座城市,编号从 1 到 n ,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。、
输入格式
第一行有两个用一个空格隔开的整数 n,m ,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x,y,z ,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意: x 不等于 y ,两座城市之间可能有多条道路 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。
输出格式
共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出 -1 。
样例输入
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
样例输出
3
-1
3
思路分析
首先便是想到了Floyd的暴力方法,状态转移方程也不难推出:w[i][j]=min(w[i][j], w[i][k]+w[k][j]);但是 n^3次方时间复杂度和 n^2 的空间复杂度是显然不可取的。
于是我们思考,可以发现有一些权值较小的边是不会被走过的。正如样例中的第三条边,就算有其他的很多条边,这条边无论如何也是不会被走过的。于是我们想到了可以将图中这样的边去掉,按照这个思路我们便想到了构造最大生成树,将其余的边去除。
得到了这样一个树之后,我们便考虑如何求出两个节点之间最小边权的最大值(即为题中的最大载重),因为这两点之间的路径是唯一的,我们只需要找出这条路径便可以得到答案。我们可以通过LCA来做到这一点,我求LCA的方法是先从每一个根节点进行搜索,求出节点深度等信息,然后利用这些信息进行树上倍增。
于是我们可以得出大体思路:首先重新建图,构造出最大生成树,然后在最大生成树上求LCA来回答询问。
#include <cstdio>
int w[100001][21],p[100001][21],head[1000001],deep[1000001],fa[1000001];
struct nodea{ int x,y,c; } t[1000001];
struct nodeb{ int x,y,c,g; } h[1000001];
int inf=999999999,len=0,n=0,m=0,q=0;
void px(int l,int r)
{
int x=l,y=r,mid=t[(l+r)/2].c;
while(x<=y)
{
while(t[x].c>mid)
{
x++;
}
while(t[y].c<mid)
{
y--;
}
if(x<=y)
{
nodea pt=t[x];
t[x]=t[y];
t[y]=pt;
x++;
y--;
}
}
if(l<y)
{
px(l,y);
}
if(x<r)
{
px(x,r);
}
}
int min(int x,int y)
{
return x<y?x:y;
}
int init()
{
for(int i=1;i<=n;i++)
{
fa[i]=i;
head[i]=0;
deep[i]=0;
}
}
void ins(int x,int y,int c)
{
len++;
h[len].x=x;
h[len].y=y;
h[len].c=c;
h[len].g=head[x];
head[x]=len;
}
int find(int t)
{
if(fa[t]==t)
{
return t;
}
else
{
return fa[t]=find(fa[t]);
}
}
void kruskal()
{
int p=0;
for(int i=1;i<=m;i++)
{
int tx=find(t[i].x);
int ty=find(t[i].y);
if(tx!=ty)
{
fa[tx]=ty;
ins(t[i].x,t[i].y,t[i].c);
ins(t[i].y,t[i].x,t[i].c);
p++;
if(p==n-1)
{
break;
}
}
}
}
void dfs(int u)
{
for(int i=head[u];i>0;i=h[i].g)
{
int y=h[i].y;
if(deep[y]==0)
{
deep[y]=deep[u]+1;
p[y][0]=u;
w[y][0]=h[i].c;
dfs(y);
}
}
}
void ycl()
{
for(int i=1;i<=n;i++)
{
if(deep[i]==0)
{
deep[i]=1;
p[i][0]=0;
dfs(i);
}
}
dfs(1);
for(int i=1;i<=20;i++)
{
for(int x=1;x<=n;x++)
{
p[x][i]=p[p[x][i-1]][i-1];
w[x][i]=min(w[x][i-1],w[p[x][i-1]][i-1]);
}
}
}
int lca(int x,int y)
{
int ans=inf;
if(deep[x]<deep[y])
{
int t=x;
x=y;
y=t;
}
for(int i=20;i>=0;i--)
{
if(deep[p[x][i]]>=deep[y])
{
ans=min(ans,w[x][i]);
x=p[x][i];
}
}
if(x==y)
{
return ans;
}
for(int i=20;i>=0;i--)
{
if(p[x][i]!=p[y][i])
{
ans=min(ans,min(w[x][i],w[y][i]));
x=p[x][i];
y=p[y][i];
}
}
ans=min(ans,min(w[x][0],w[y][0]));
return ans;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&t[i].x,&t[i].y,&t[i].c);
}
px(1,m);
init();
kruskal();
ycl();
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int dx=0,dy=0;
scanf("%d %d",&dx,&dy);
if(find(dx)!=find(dy))
{
printf("-1\n");
}
else
{
printf("%d\n",lca(dx,dy));
}
}
return 0;
}