Educational Codeforces Round 51 (Rated for Div. 2) F. The Shortest Statement(最短路+LCA+思维)

题目链接
在这里插入图片描述
在这里插入图片描述
思路:由于m-n小于20,两点之间的最短路只有两种情况。1、两点的最短路不经过非树边,那么最短路用lca求就行了,2、如果至少经过一条非树边呢?这题精华就在这儿,由于m-n小于20,最多只有40个点连这非树边,于是对这些点求spfa,最多执行40遍spfa,再进行比较就行了,这里说一下经过非树边的最短路是d【i】【x】+d【i】【y】,表示的是以i为顶点到x的最短距离+到y的最短距离。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll; 
const int maxn=1e5+1;
int n,deep[maxn],parent[maxn][26];
vector<pair<int,ll> >g[maxn];
vector<int>p;
ll w,weight[maxn],d[44][maxn];
bool vis[maxn];
void dfs(int u,int fa)
{
	deep[u]=deep[fa]+1;
	parent[u][0]=fa;
	for(auto to:g[u])
	{
		if(to.first==fa) continue;
		if(!deep[to.first]) weight[to.first]=weight[u]+to.second,dfs(to.first,u);
		else p.push_back(u),p.push_back(to.first);
	}
}
void init()
{
	for(int k=1;k<=21;++k)
	for(int i=1;i<=n;++i)
	parent[i][k]=parent[parent[i][k-1]][k-1];
}
int lca(int u,int v)
{
	if(deep[u]<deep[v]) swap(u,v);
	if(u!=v)
	for(int i=21;i>=0;--i) if(deep[parent[u][i]]>=deep[v]) u=parent[u][i];
	if(u==v) return u;
	for(int i=21;i>=0;--i)
	if(parent[u][i]!=parent[v][i]) u=parent[u][i],v=parent[v][i];
	return parent[u][0];
}
ll getdis(int x,int y)
{
	return weight[x]+weight[y]-2*weight[lca(x,y)];
}
void spfa(int x,int id)
{
	memset(vis,false,sizeof(vis));
	memset(d[id],0x3f3f3f3f,sizeof(d[id]));
	d[id][x]=0;
	queue<int>q;
	q.push(x);
	vis[x]=true;
	while(!q.empty())
	{
		int top=q.front();
		q.pop();
		vis[top]=false;
		for(auto v:g[top])
		{
			if(d[id][top]+v.second<d[id][v.first])
			{
				d[id][v.first]=d[id][top]+v.second;
				if(!vis[v.first]) q.push(v.first),vis[v.first]=true;
			}
		}
	}
}
int main()
{
	int m,u,v,q,x,y;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;++i)
	{
		scanf("%d %d %lld",&u,&v,&w);
		g[u].push_back({v,w});
		g[v].push_back({u,w});
	}
	weight[1]=0,deep[1]=1;
	dfs(1,0);
	init();
	sort(p.begin(),p.end());
	p.erase(unique(p.begin(),p.end()),p.end());
	for(int i=0;i<p.size();++i) spfa(p[i],i);
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d %d",&x,&y);
		ll ans=getdis(x,y);
		for(int i=0;i<p.size();++i)
		ans=min(ans,d[i][x]+d[i][y]);
		printf("%lld\n",ans);
	}
}
发布了283 篇原创文章 · 获赞 0 · 访问量 7289

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/105127433