給定一個\(n\)個點、\(m\)條邊的帶權無向圖,其中有\(s\)個點是加油站。每輛車都有一個油量上限\(b\),即每次行走距離不能超過\(b\),但在加油站能夠補滿。\(q\)次詢問,每次給出\(x,y,b\),表示出發點是\(x\),終點是\(y\),油量上限爲\(b\),且保證\(x\)點和\(y\)點都是加油站,請回答可否從\(x\)走到\(y\)。(\(2 \le s \le n \le 200000, 1 \le m \le 200000\))c++
首先來分析若是隻有一個詢問,給出\(x\)點和\(y\)點問\(x\)是否能走到\(y\)。假設通過的非加油站的點集依次是\(p_1, p_2, \cdots, p_k\),那麼考慮從\(p_1\)走到\(p_2\),假設有邊\((p_1, p_2)\)(不然必定是從加油站走到\(p_2\)的),權值爲\(w\)。若是咱們從\(p_1\)走到最近的加油站(距離爲\(d(p_1)\))加滿油再回來,還剩的油爲\(b-d(p_1)\),而後再走這條邊。而若是直接從\(p_1\)走到\(p_2\),因爲沒有加油,此時在\(p_1\)的油量顯然是\(\le b-d(p_1)\)的。顯然加了油更優。spa
根據分析,咱們只須要按新賦值的邊權w+d(u)+d(v)生成最小生成樹來判斷便可。對於詢問,離線一下便可。code
#include <bits/stdc++.h> using namespace std; const int N=200005, M=200005; int ihead[N], cnt, n, m, s, p[N], h[N], c[N]; struct E { int next, to, w; }e[M<<1]; struct ED { int x, y, d; }ed[M]; struct QU { int x, y, b, id; }q[N]; void add(int x, int y, int w) { e[++cnt]=(E){ihead[x], y, w}; ihead[x]=cnt; e[++cnt]=(E){ihead[y], x, w}; ihead[y]=cnt; } int find(int x) { return x==p[x]?x:p[x]=find(p[x]); } typedef pair<int, int> pii; #define mkpii make_pair<int, int> priority_queue<pii, vector<pii>, greater<pii> > qu; int d[N], vis[N]; void dij() { memset(d, 0x7f, sizeof(int)*(n+1)); for(int i=0; i<s; ++i) { d[c[i]]=0; qu.push(mkpii(0, c[i])); } while(qu.size()) { int x=qu.top().second; qu.pop(); if(vis[x]) { continue; } vis[x]=1; for(int i=ihead[x]; i; i=e[i].next) { int y=e[i].to; if(d[y]>d[x]+e[i].w) { d[y]=d[x]+e[i].w; qu.push(mkpii(d[y], y)); } } } } inline bool cmp1(const ED &a, const ED &b) { return a.d<b.d; } inline bool cmp2(const QU &a, const QU &b) { return a.b<b.b; } int ans[N]; int main() { scanf("%d%d%d", &n, &s, &m); for(int i=1; i<=n; ++i) { p[i]=i; h[i]=1; } for(int i=0; i<s; ++i) { scanf("%d", &c[i]); } for(int i=0; i<m; ++i) { scanf("%d%d%d", &ed[i].x, &ed[i].y, &ed[i].d); add(ed[i].x, ed[i].y, ed[i].d); } dij(); for(int i=0; i<m; ++i) { ed[i].d+=d[ed[i].x]+d[ed[i].y]; } int Q; scanf("%d", &Q); for(int i=0; i<Q; ++i) { scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].b); q[i].id=i; } sort(ed, ed+m, cmp1); sort(q, q+Q, cmp2); int now=0; for(int i=0; i<Q; ++i) { while(now<m && ed[now].d<=q[i].b) { int fx=find(ed[now].x), fy=find(ed[now].y); if(fx!=fy) { if(h[fx]>h[fy]) { swap(fx, fy); } p[fx]=fy; h[fy]+=h[fy]==h[fx]; } ++now; } ans[q[i].id]=find(q[i].x)==find(q[i].y); } for(int i=0; i<Q; ++i) { puts(ans[i]?"TAK":"NIE"); } return 0; }