P1967 貨車運輸(Tarjan做法)
阿新 • • 發佈:2019-02-05
傳送門
這個問題叫做『最大瓶頸路徑』
最大瓶頸路徑一定存在於最大生成樹中/反證法:如果最大瓶頸路徑不存在與最大生成樹中。
這些不在最大生成樹中的邊會和最大生成樹形成環。
我們刪掉環上最小的邊,保留這一條邊,會得到一棵新的更大的生成樹。
這與原來那棵樹是最大生成樹矛盾了。
注意,最短路不一定在最小生成樹上(如一個環的情況)
現在問題轉變為求樹上兩點的最小邊權問題了。
很明顯是從u->LCA(u,v)->v這條路能使最小邊權最大。
我們先用Tarjan求出LCA.記錄下來。
用一個數組記錄DFS遍歷的前一個節點和邊權,然後遞迴分別找u->LCA(u,v)的最小權值,v->LCA(u,v)的最小權值
兩者取min即為答案。
需要注意的是,加入詢問的兩個點不在一顆樹上,Tarjan跑出的LCA其實是不對的,所以要在最後輸出時去判斷一下是否在一棵樹中。
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxm=510000;
struct Node{
int net;
int to;
int cost;
int lca;
int ans;
};
bool vis[maxm];
Node edge[2][2*maxm];
int cnt[2],head[2 ][maxm],n,m;
int fatt[maxm],fat[maxm],dis[maxm];
int Dis1,Dis2;
int ansx[maxm],ansy[maxm];
int fatx[maxm];
void add(int id,int x,int y,int c)
{
edge[id][++cnt[id]].to=y;
edge[id][cnt[id]].cost=c;
edge[id][cnt[id]].net=head[id][x];
head[id][x]=cnt[id];
}
struct node{
int x,y,z;
}a[maxm];
int find1(int x)
{
if(x==fatt[x]) return x;
return fatt[x]=find1(fatt[x]);
}
int findx(int x)
{
if(x==fatx[x]) return x;
else
return fatx[x]=findx(fatx[x]);
}
int find(int id,int x,int fs)
{
if(id==0)
{
Dis1=1e17;
while(fat[x]!=x&&fs!=x)
{
Dis1=min(Dis1,dis[x]);
x=fat[x];
}
return x;
}
else
{
Dis2=1e17;
while(fat[x]!=x&&fs!=x)
{
Dis2=min(Dis2,dis[x]);
x=fat[x];
}
return x;
}
}
bool comp(const node&x,const node&y)
{
return x.z>y.z;
}
void dfs(int x)
{
vis[x]=1;
fat[x]=x;
fatx[x]=x;
for(int K=head[0][x];K;K=edge[0][K].net)
{
int p=edge[0][K].to;
if(vis[p]) continue;
dfs(p);
fatx[p]=x;
fat[p]=x;
dis[p]=edge[0][K].cost;
}
for(int i=head[1][x];i;i=edge[1][i].net)
{
int p=edge[1][i].to;
if(!vis[p]) continue;
//int ans=min(Dis1,Dis2);
//edge[1][i].ans=ans;
edge[1][i].lca=findx(p);
ansx[i]=x,ansy[i]=p;
if(i%2)
edge[1][i+1].lca=edge[1][i].lca,ansx[i+1]=x,ansy[i+1]=p;
else
edge[1][i-1].lca=edge[1][i].lca,ansx[i-1]=x,ansy[i-1]=p;
}
}
int main()
{
//freopen("truck.in","r",stdin);
//freopen("truck.out","w",stdout);
int maxf=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fatt[i]=i,fat[i]=i,fatx[i]=i;
for(int i=1,x,y,z;i<=m;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
sort(a+1,a+m+1,comp);
int tot=0;
for(int i=1;i<=m&&tot!=n-1;i++)
if(find1(a[i].x)!=find1(a[i].y))
{
fatt[find1(a[i].x)]=find1(a[i].y);
add(0,a[i].x,a[i].y,a[i].z);add(0,a[i].y,a[i].x,a[i].z);
tot++;
}
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(1,x,y,0),add(1,y,x,0);
}
for(int i=1;i<=n;i++)
if(!vis[i])
dfs(i);
for(int i=1;i<=t;i++)
if(findx(ansx[2*i])!=findx(ansy[2*i]))
printf("-1\n");
else
{
find(0,ansx[2*i],edge[1][2*i].lca);
find(1,ansy[2*i],edge[1][2*i].lca);
printf("%d\n",min(Dis1,Dis2));
}
}