CodeForces - 1051F The Shortest Statement(最短路,lca)

版权声明:选经典题目,写精品文章. https://blog.csdn.net/nka_kun/article/details/82827287

给出一个图,询问任意两点之间最短路,边比点多不过20

题意:给出一个图,询问任意两点之间最短路,边比点多不过20.
思路:因为边多的很少,所以可以看成一个树,又多加了几条边.这样其实我们可以把那几个点看成中转节点,这样我们可以求出那些点到任意点的最短路径,然后询问的时候,对于x,y,要不从树上直接从x,y这里用lca即可,要么经过其中一个节点,为什么不是结果其中几个节点呢?其实经过一个节点就够了,那个节点到任意节点的最短路我们是知道的,他如果需要会自动经过几个节点的.

代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;

struct edge
{
	int u,v,ne;
	ll w;
}e[maxn];

struct node
{
	int pos;
	ll cost;
	node(){}
	node(int x,ll y):pos(x),cost(y){}
	friend bool operator < (node x,node y)
	{
		return x.cost> y.cost;
	}
};

int n,m;
int head[maxn],len;
ll v[maxn][3],d[maxn],dis[45][maxn];
int vis[maxn],pre[maxn];
bool book[maxn];
int deep[maxn],f[maxn],anc[maxn][20];

int find(int x)
{
	return pre[x] == x?x:pre[x] = find(pre[x]);
}

void add(int u,int v,ll w)
{
	e[len].u = u;
	e[len].v = v;
	e[len].w = w;
	e[len].ne = head[u];
	head[u] = len++;
}

void dfs(int x,int p,ll w)
{
	deep[x] = deep[p]+1; 
	f[x] = p;
	anc[x][0] = p;
	d[x] = w;
	
	for(int i = 1;i<= 19;i++)
		anc[x][i] = anc[anc[x][i-1]][i-1];
	
	for(int i = head[x];i!= -1;i = e[i].ne)
	{
		if(e[i].v == p) continue;
		dfs(e[i].v,x,w+e[i].w);
	}
	return ;
}

int lca(int x,int y)
{
	if(deep[x]< deep[y])
		swap(x,y);
	
	for(int i = 19;i>= 0;i--)
		if(deep[x]-(1<<i)>= deep[y])
			x = anc[x][i];
	if(x == y) return x;
	for(int i = 19;i>= 0;i--)
		if(anc[x][i]!= anc[y][i])
			x = anc[x][i],y = anc[y][i];
	return anc[x][0];
}


void DJ(int sx,int t)
{
	for(int i = 1;i<= n;i++) dis[t][i] = 1e15;
	mem(book,0);
	priority_queue<node> q;
	q.push(node(sx,0));
	dis[t][sx] = 0;
	
	while(!q.empty())
	{
		node now = q.top();
		q.pop();
		
		if(book[now.pos]) continue;
		book[now.pos] = 1;
		for(int i = head[now.pos];i!= -1;i = e[i].ne)
		{
			int id = e[i].v;
			if(dis[t][id]> dis[t][now.pos]+e[i].w)
			{
				dis[t][id] = dis[t][now.pos]+e[i].w;
				q.push(node(id,dis[t][id]));
			}		
		}
	}
	
	return ;
}

int main()
{
	mem(head,-1);
	cin>>n>>m;
	for(int i = 1;i<= n;i++) pre[i] = i;
	for(int i = 1;i<= m;i++)
		scanf("%lld %lld %lld",&v[i][0],&v[i][1],&v[i][2]);
	for(int i = 1;i<= m;i++)
	{
		int fx = find(v[i][0]);
		int fy = find(v[i][1]);
		if(fx!= fy)
		{
			vis[i] = 1;
			pre[fy] = fx;
			add((int)v[i][0],(int)v[i][1],v[i][2]);
			add((int)v[i][1],(int)v[i][0],v[i][2]);
		}
	}
	
	dfs(1,0,0);
	
	for(int i = 1;i<= m;i++)
	{
		if(!vis[i])
		{
			add((int)v[i][0],(int)v[i][1],v[i][2]);
			add((int)v[i][1],(int)v[i][0],v[i][2]);
		}
	}
	
	int cnt = 0;
	for(int i = 1;i<= m;i++)
	{
		if(!vis[i])
		{
			cnt++;
			DJ((int)v[i][0],cnt);
			cnt++;
			DJ((int)v[i][1],cnt);
		}
	}
	
	int q;
	cin>>q;
	while(q--)
	{
		int x,y;
		scanf("%d %d",&x,&y);
		
		int fa = lca(x,y);
		ll ans = d[x]-d[fa]+d[y]-d[fa];
		
		for(int i = 1;i<= cnt;i++)
			ans = min(dis[i][x]+dis[i][y],ans);
		printf("%lld\n",ans);
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nka_kun/article/details/82827287