AcWing 1488. 最短距离
宋标 Lv5

题目

个村庄,编号

村庄之间有 无向道路,第 条道路连接村庄 和村庄 ,长度是

所有村庄都是连通的。

共有 个村庄有商店,第 个有商店的村庄编号是

然后给出 个询问,第 个询问给出一个村庄的编号 ,问该村庄距离最近的商店有多远?

输入格式

第一行包含两个整数

接下来 行,每行包含三个整数 ,表示第 条道路连接村庄 和村庄 ,长度是

再一行包含整数

接下来 行,每行包含一个整数 ,表示第 个有商店的村庄编号是

再一行包含整数

接下来 行,每行包含一个整数 ,表示询问编号为 的村庄与其距离最近的商店之间的距离。

输出格式

对于每个询问,输出该询问的结果。

数据范围

,
,
,
,

输入样例:

7 7
1 2 5
1 4 3
2 3 2
2 5 1
3 6 7
5 6 8
6 7 6
3
7
5
4
7
1
2
3
4
5
6
7

输出样例:

3
1
3
0
0
6
0

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include <cstring>

using namespace std;

// N个节点,M = N条无向边+N条有向边(超级源点指向商店)
const int N = 100010, M = 300010;

int h[N], e[M], w[M], ne[M], idx;
int dist[N], q[N];
bool st[N];

void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}

void spfa()
{
memset(dist, 0x3f, sizeof dist);
dist[0] = 0;

int hh = 0, tt = 1;
while (hh != tt)
{
int t = q[hh ++];
if (hh == N) hh = 0;

// 至于为什么设置为false,思考很久
// 最后得出一个简单的结论, 只需要考虑队列中只存放当前最短路径(且后续可能会被更新),且保证队列中不会存在重复节点
st[t] = false;

for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if (!st[j])
{
q[tt ++] = j;
if (tt == N) tt = 0;
st[j] = true;
}
}
}
}

}

int main()
{
memset(h, -1, sizeof h);

int n, m;
scanf("%d%d", &n, &m);
while (m --)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}

scanf("%d", &m);
while (m --)
{
int x;
scanf("%d", &x);
add(0, x, 0);
}

spfa();

scanf("%d", &m);
while (m --)
{
int k;
scanf("%d", &k);
printf("%d\n", dist[k]);
}

return 0;
}
 评论