题解 最小距离

传送门

考试时思路是从每个点BFS,浸染当前与它最近的点,但复杂度有点假

其实这个过程可以一次dijkstra完成,利用多源最短路
每个特殊点都是一个源点,扩展时记录一下是从哪个源点扩展过来的
统计答案时枚举所有两端点不是由同一源点扩展的边即可
挺好的题,可惜没想出来

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long 
#define fir first
#define sec second 
#define make make_pair
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, p;
int x[N], head[N], size=1, back[N];
bool vis[N];
ll dis[N], ans[N];
struct edge{int from, to, next; ll val;}e[N<<1];
inline void add(int s, int t, ll w) {e[++size].to=t; e[size].from=s; e[size].val=w; e[size].next=head[s]; head[s]=size;}
struct cmp{inline bool operator () (pair<ll, int> a, pair<ll, int> b) {return a.fir>b.fir;}};

void dijkstra() {
	memset(dis, 127, sizeof(dis));
	priority_queue< pair<ll, int> , vector< pair<ll, int> >, cmp> q;
	for (int i=1; i<=p; ++i) dis[x[i]]=0, back[x[i]]=x[i], q.push(make(0, x[i]));
	while (q.size()) {
		int t=q.top().sec; q.pop();
		//cout<<"t: "<<t<<' '<<dis[t]<<endl;
		if (vis[t]) continue;
		vis[t]=1;
		for (int i=head[t],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (vis[v]) continue;
			if (dis[v] > dis[t]+e[i].val) {
				dis[v]=dis[t]+e[i].val; back[v]=back[t];
				q.push(make(dis[v], v));
			}
		}
	}
}

signed main()
{
	memset(head, -1, sizeof(head));
	memset(ans, 127, sizeof(ans));
	
	n=read(); m=read(); p=read();
	for (int i=1; i<=p; ++i) x[i]=read();
	for (int i=1,u,v,w; i<=m; ++i) {
		u=read(); v=read(); w=read();
		add(u, v, w); add(v, u, w);
	}
	dijkstra();
	ll t;
	for (int i=2; i<=size; ++i) if (i&1 && back[e[i].from]!=back[e[i].to]) {
		//cout<<"diff "<<back[e[i].from]<<' '<<back[e[i].to]<<endl;
		t = dis[e[i].from]+dis[e[i].to]+e[i].val;
		ans[back[e[i].from]]=min(ans[back[e[i].from]], t);
		ans[back[e[i].to]]=min(ans[back[e[i].to]], t);
	}
	for (int i=1; i<=p; ++i) printf("%lld ", ans[x[i]]);
	printf("\n");
	
	return 0;
}
posted @ 2021-08-12 20:16  Administrator-09  阅读(9)  评论(0编辑  收藏  举报