1. 程式人生 > 其它 >【Luogu P1967】貨車運輸

【Luogu P1967】貨車運輸

https://www.luogu.com.cn/problem/P1967

分析

題意為求任意兩城市之間能夠聯通的線路中所有單個線路中最小值的最大值。
首先做最大生成樹生成陣列\(tree\),然後\(dfs\)每棵樹獲得陣列\(deep\)(\(deep[i]\)表示\(i\)節點在所屬的樹中的深度,根節點深度為\(0\)),\(mindist[i][0]\)(\(mindist[i][j]\)表示從節點\(i\)向上走\(2^j\)步過程中所經歷的路徑的最小值),\(p[x][0]\)(\(p[x][y]\)表示從節點\(x\)向上走\(2^y\)步所到達的節點)。
查詢時首先用並查集判斷是否能聯通,然後用\(lca\)

查詢到最近公共祖先,並且由\(mindist\)陣列知道這一過程中所有單個線路中的最小值(實際在最大生成樹\(tree\)陣列上查詢)。

#include <bits/stdc++.h>
#define P pair<int, int>
#define PI pair<int,P>
#define INF 0x3fffffff
using namespace std;  
int n,m,x,y,d,q,deep[10010],p[10010][15],fa[10010],mdep=0,mindist[10010][15];
vector<PI> V; //dis node1 node2 
vector<P> tree[10010]; //dis node
vector<int> root;
int find(int n)
{
	return fa[n]==n?n:fa[n]=find(fa[n]);
}
void build()
{
	//cout<<V.size()<<endl;
	for(auto tmp=V.rbegin();tmp<V.rend();tmp++)
	{
		int di=tmp->first,a=tmp->second.first, b=tmp->second.second;
		if(find(a)!=find(b))
		{
			//cout<<a<<" "<<b<<" "<<di<<endl;
			tree[a].push_back(P(di,b));
			tree[b].push_back(P(di,a));
			fa[find(a)]=find(b);
		}	
	}
}
void dfs(int r,int fa)
{
	p[r][0]=fa;
	deep[r]=deep[fa]+1;
	if(deep[r]>mdep)mdep=deep[r];
	for(auto x:tree[r])
	{
		if(x.second!=fa)
		{
			mindist[x.second][0]=x.first;
			dfs(x.second,r);	
		}
	}
}
int query(int a,int b)
{
	int ans=INF;
	if(deep[a]<deep[b])swap(a,b);
	//a>=b
	int i=0;
	for(;(1<<i)<=deep[a];i++);
	i--;
	for(int k=i;k>=0;k--)
	{
		if(deep[a]-(1<<k)>=deep[b])
		{
			ans=min(ans,mindist[a][k]);
			a=p[a][k];
		}
	}
	if(a==b)return ans;
	for(int k=i;k>=0;k--)
	{
		if(deep[a]>=(1<<k)&&p[a][k]!=p[b][k])
		{
			ans=min(min(ans,mindist[a][k]),mindist[b][k]);
			a=p[a][k];
			b=p[b][k];
		} 
	}
	ans=min(ans,min(mindist[a][0],mindist[b][0]));
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	//get edges
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%d",&x,&y,&d);
		V.push_back(PI(d,P(x,y)));
	}
	sort(V.begin(),V.end());
	for(int i=1;i<=n;i++)fa[i]=i;
	//build tree
	build();
	deep[0]=-1;
	for(int i=1;i<=n;i++)
		if(fa[i]==i)dfs(i,0); //set i node as root => deep and p[x][0](father)
	int j=1,k=2;//k=2^j
	while(k<=mdep)
	{
		for(int i=1;i<=n;i++)
		{
			if(deep[i]>=k)
			{
				p[i][j]=p[p[i][j-1]][j-1];
				mindist[i][j]=min(mindist[i][j-1],mindist[p[i][j-1]][j-1]);	
			}
		}
		j++;
		k*=2;
	}
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d%d",&x,&y);
		if(find(x)!=find(y))printf("-1\n");
		else printf("%d\n",query(x,y));
	}
    return 0;
}