bzoj4144 [AMPPZ2014]Petrol
Description
給定一個 \(n\)個 點、 \(m\) 條邊的帶權無向圖,其中有 \(s\) 個點是加油站。
每輛車都有一個油量上限 \(b\) ,即每次行走距離不能超過 \(b\) ,但在加油站可以補滿。
\(q\) 次詢問,每次給出 \(x,y,b\) ,表示出發點是 \(x\) ,終點是 \(y\) ,油量上限為 \(b\) ,且保證 \(x\) 點和 \(y\) 點都是加油站,請回答能否從 \(x\) 走到 \(y\) 。
Input
第一行包含三個正整數 \(n,s,m(2\le s\le n\le 200000,1\le m\le 200000)\) ,表示點數、加油站數和邊數。
第二行包含 \(s\)
接下來 \(m\) 行,每行三個正整數 \(u[i],v[i],d[i](1\le u[i],v[i]\le n,u[i]\ne v[i],1\le d[i]\le 10000)\) ,表示 \(u[i]\) 和 \(v[i]\) 之間有一條長度為 \(d[i]\) 的雙向邊。
接下來一行包含一個正整數 \(q(1\le q\le 200000)\) ,表示詢問數。
接下來 \(q\) 行,每行包含三個正整數 \(x[i],y[i],b[i](1\le x[i],y[i]\le n,x[i]\ne y[i],1<\le b[i]\le 2\times 10^9)\)
Output
輸出 \(q\) 行。第 \(i\) 行輸出第i個詢問的答案,如果可行,則輸出 \(\mathrm{TAK}\) ,否則輸出 \(\mathrm{NIE}\) 。
Sample
Sample Input
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
TAK
TAK
TAK
NIE
Solution
真是一道結論詭好題。
大家肯定知道,不是加油站的點是廢點。那加油站點該怎麽重新建圖呢?
來看一個圖。紅點表示加油站,黑點是廢點。
從 \(1\)
- 從當前節點到最近的加油站再到其它的加油站不會更差
那麽就可以多源最短路,最小生成樹判斷連通性就可以了。
具體細節見代碼。
#include<bits/stdc++.h>
using namespace std;
#define N 400011
#define rep(i, a, b) for (int i = a; i <= b; i++)
inline int read() {
int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
}
int n, s, m, C[N], head[N], tot = 1, cnt, dis[N], near[N], fa[N];
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
queue<int> q;
bool inq[N], ans[N];
struct edge { int v, w, next; }e[N];
inline void add(int u, int v, int w) { e[++tot].v = v, e[tot].w = w, e[tot].next = head[u], head[u] = tot; }
struct edgeData {
int u, v, w;
edgeData(int _u = 0, int _v = 0, int _w = 0):u(_u), v(_v), w(_w) {}
bool operator < (const edgeData& b) const { return w < b.w; }
}edt[N];
struct query {
int id, S, T, d;
bool operator < (const query& b) const { return d < b.d; }
}qu[N];
void spfa() {
rep(i, 1, n) dis[i] = 0x7fffffff;
rep(i, 1, s) q.push(C[i]), inq[C[i]] = 1, dis[C[i]] = 0, near[C[i]] = C[i];
while (!q.empty()) {
int u = q.front(); q.pop(), inq[u] = 0;
for (int i = head[u], v; i; i = e[i].next) if (dis[v = e[i].v] > dis[u] + e[i].w) {
dis[v] = dis[u] + e[i].w, near[v] = near[u];
if (!inq[v]) q.push(v), inq[v] = 1;
}
}
rep(u, 1, n) for (int i = head[u], v; i; i = e[i].next) if (near[u] ^ near[v = e[i].v])
edt[++cnt] = edgeData(near[u], near[v], dis[u] + dis[v] + e[i].w);
sort(edt + 1, edt + 1 + cnt);
}
int main() {
n = read(), s = read(), m = read();
rep(i, 1, n) fa[i] = i;
rep(i, 1, s) C[i] = read();
rep(i, 1, m) { int u = read(), v = read(), w = read(); add(u, v, w), add(v, u, w); }
spfa();
int q = read();
rep(i, 1, q) qu[i].S = read(), qu[i].T = read(), qu[i].d = read(), qu[i].id = i;
sort(qu + 1, qu + 1 + q);
int pos = 1;
rep(i, 1, q) {
while (pos <= cnt && edt[pos].w <= qu[i].d) {
int x = find(edt[pos].u), y = find(edt[pos].v);
if (x ^ y) fa[x] = y;
pos++;
}
ans[qu[i].id] = (find(qu[i].S) == find(qu[i].T));
}
rep(i, 1, q) puts(ans[i] ? "TAK" : "NIE");
return 0;
}
bzoj4144 [AMPPZ2014]Petrol