BZOJ4144【AMPPZ2014】Petrol < 最短路+MST >

Problem

【AMPPZ2014】Petrol

Time  Limit:  10  Sec\mathrm{Time\;Limit:\;10\;Sec}
Memory  Limit:  256  MB\mathrm{Memory\;Limit:\;256\;MB}

Description

给定一个nn个点、mm条边的带权无向图,其中有ss个点是加油站。
每辆车都有一个油量上限bb,即每次行走距离不能超过bb,但在加油站可以补满。
qq次询问,每次给出x,y,bx,y,b,表示出发点是xx,终点是yy,油量上限为bb,且保证xx点和yy点都是加油站,请回答能否从xx走到yy

Input

第一行包含三个正整数n,s,mn,s,m(2sn2×1052\le s\le n\le 2\times 10^5,1m2×1051\le m\le 2\times 10^5),表示点数、加油站数和边数。
第二行包含ss个互不相同的正整数c[1],c[2],...c[s]  (1c[i]n)c[1],c[2],...c[s]\;(1\le c[i]\le n),表示每个加油站。
接下来mm行,每行三个正整数u[i]u[i],v[i]v[i],d[i]d[i](1u[i],v[i]n1\le u[i],v[i]\le n,u[i]v[i]u[i]\ne v[i],1d[i]1051\le d[i]\le 10^5),表示u[i]u[i]v[i]v[i]之间有一条长度为d[i]d[i]的双向边。
接下来一行包含一个正整数qq(1q2×1051\le q\le 2\times 10^5),表示询问数。
接下来qq行,每行包含三个正整数x[i],y[i],b[i]x[i],y[i],b[i](1x[i],y[i]n1\le x[i],y[i]\le n,x[i]y[i]x[i]\ne y[i],1b[i]2×1091\le b[i]\le 2\times 10^9),表示一个询问。

Output

输出qq行。第ii行输出第ii个询问的答案,如果可行,则输出TAK\mathrm{TAK},否则输出NIE\mathrm{NIE}

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
6 4 5
1 5 2 6
1 3 1
2 3 2
3 4 3
4 5 5
6 4 5
4
1 2 4
2 6 9
1 5 9
6 5 8

Sample Output

1
2
3
4
TAK
TAK
TAK
NIE

标签:最短路 MST

Solution

一道精妙的MST\mathrm{MST}题。
首先考虑走到一个点,先去离它最近的加油站,回来后再去下一个点肯定比直接去要优。
于是用多源最短路预处理出每个点到它最近的加油站的距离,随后给每一条边分别加上它的起点和终点离它们最近加油站的距离。
对于询问,先离线下来按bb值排序,按照边权加入边,用并查集维护。对于每个询问,先将比它的bb值小的所有边都加入,再询问起点和终点是否联通即可。

Code

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
#include <bits/stdc++.h>
#define fir first
#define sec second
#define mp make_pair
#define pii pair<int,int>
#define MAX_N 200000
using namespace std;
int n, m, s, c[MAX_N+5], fa[MAX_N+5], dis[MAX_N+5]; vector <pii> G[MAX_N+5];
struct edge {int u, v, c; bool operator < (const edge &t) const {return c < t.c;}} E[MAX_N+5];
struct query {int id, u, v, c; bool operator < (const query &t) const {return c < t.c;}} Q[MAX_N+5];
int getf(int x) {return fa[x] == x ? x : fa[x] = getf(fa[x]);}
void Dijkstra() {
priority_queue <pii> que; bool mrk[MAX_N+5];
memset(dis, 0x7f, sizeof dis), memset(mrk, false, sizeof mrk);
for (int i = 1; i <= s; i++) dis[c[i]] = 0, que.push(mp(-dis[c[i]], c[i]));
while (!que.empty()) {
int u = que.top().sec; que.pop();
if (mrk[u]) continue; mrk[u] = true;
for (int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i].fir, w = G[u][i].sec;
if (dis[u]+w < dis[v]) dis[v] = dis[u]+w, que.push(mp(-dis[v], v));
}
}
}
int main() {
scanf("%d%d%d", &n, &s, &m); for (int i = 1; i <= s; i++) scanf("%d", c+i);
for (int i = 1; i <= m; i++) scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].c), G[E[i].u].push_back(mp(E[i].v, E[i].c)), G[E[i].v].push_back(mp(E[i].u, E[i].c));
Dijkstra(); for (int i = 1; i <= m; i++) E[i].c += dis[E[i].u]+dis[E[i].v];
int q; scanf("%d", &q); for (int i = 1; i <= q; i++) Q[i].id = i, scanf("%d%d%d", &Q[i].u, &Q[i].v, &Q[i].c);
sort(E+1, E+m+1), sort(Q+1, Q+q+1); for (int i = 1; i <= n; i++) fa[i] = i; bool ans[MAX_N+5];
for (int i = 1, j = 1; i <= q; i++) {
for (int u, v; j <= m && E[j].c <= Q[i].c; j++)
if ((u = getf(E[j].u)) != (v = getf(E[j].v))) fa[u] = v;
ans[Q[i].id] = getf(Q[i].u) == getf(Q[i].v);
}
for (int i = 1; i <= q; i++) puts(ans[i] ? "TAK" : "NIE");
return 0;
}