BZOJphp
看別人代碼的時候發現哪一步都很眼熟,忽然想起來,就在四個月前我好像看過還給別人講過?mmp=v=
果真不寫寫就是容易忘。寫了好歹忘了的時候還能複習呢(雖然和看別人的好像也沒多少差異?)。git
首先非加油站的點是沒有用的。考慮如何刪掉這些點而後在加油站之間連對應的邊。
搬這裏的一張圖:
由於\(b<a\ \&\&\ b<c\),因此有\(b+c<a+c\ \&\&\ b+a<a+c\),也就是到一個點時,先去一次離它最近的點加油再去其它的點必定不會更差。記\(bel[p]\)爲離\(p\)點最近的加油站,\(dis[p]\)爲\(bel[p]\)到\(p\)的距離,對於一條邊\((u,v,w)\),若\(bel[u]\neq bel[v]\),那麼就在\(bel[u],bel[v]\)之間加一條\(dis[u]+dis[v]+w\)的邊便可。(由於從任何一個點出發到了\(u\),先去一次\(bel[u]\)再去別的點不會更差,因此直接和\(bel[u]\)連邊就好了)
具體就是以全部加油點爲起點,\(Dijkstra\)跑一遍多源最短路。
而後求一遍最小生成樹。詢問就判斷兩點間路徑上的最大值便可。
注意求生成樹的時候能夠直接按秩合併將樹高保持在\(O(\log n)\)的高度。對於詢問暴力跳\(fa\)便可。spa
要注意圖可能不連通!!.net
//20216kb 2600ms #include <queue> #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define mp std::make_pair #define pr std::pair<int,int> #define gc() getchar() #define MAXIN 500000 //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) typedef long long LL; const int N=2e5+5; int Enum,H[N],nxt[N<<1],to[N<<1],len[N<<1],dis[N],bel[N],F[N],fa[N],w[N],rk[N],dep[N]; char IN[MAXIN],*SS=IN,*TT=IN; std::priority_queue<pr> q; struct Edge { int u,v,w; bool operator <(const Edge &x)const { return w<x.w; } }e[N<<1];//雙向邊啊 inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-48,c=gc()); return now; } inline void AE(int w,int v,int u) { to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, len[Enum]=w; to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum, len[Enum]=w; } int Dijkstra() { static bool vis[N]; int cnt=0; while(!q.empty()) { int x=q.top().second; q.pop(); if(vis[x]) continue; vis[x]=1; for(int i=H[x],v; i; i=nxt[i]) if(dis[v=to[i]]>dis[x]+len[i]) dis[v]=dis[x]+len[i], bel[v]=bel[x], q.push(mp(-dis[v],v)); else if(bel[x]!=bel[v]) e[++cnt]=(Edge){bel[x],bel[v],dis[x]+dis[v]+len[i]}; } return cnt; } int Find(int x) { return x==F[x]?x:F[x]=Find(F[x]); } void GetDep(int x) { if(fa[x]&&!dep[fa[x]]) GetDep(fa[x]); dep[x]=dep[fa[x]]+1; } void Kruskal(const int n,const int m) { std::sort(e+1,e+1+m); for(int i=1; i<=n; ++i) F[i]=i; for(int i=1,r1,r2,k=1; i<=m; ++i) { if((r1=Find(e[i].u))==(r2=Find(e[i].v))) continue; if(rk[r1]<rk[r2]) std::swap(r1,r2);//r2->r1 else if(rk[r1]==rk[r2]) ++rk[r1]; F[r2]=r1, fa[r2]=r1, w[r2]=e[i].w; } for(int i=1; i<=n; ++i) if(!dep[i]) GetDep(i); } inline bool Query() { int u=read(),v=read(),val=read(); if(Find(u)!=Find(v)) return 0;//! if(dep[u]<dep[v]) std::swap(u,v); for(int tmp=dep[v]; dep[u]>tmp; u=fa[u]) if(w[u]>val) return 0; for(; u!=v; u=fa[u],v=fa[v]) if(w[u]>val||w[v]>val) return 0; return 1; } int main() { const int n=read(),s=read(),m=read(); memset(dis,0x7f,sizeof dis); for(int i=1,x; i<=s; ++i) dis[x=read()]=0, bel[x]=x, q.push(mp(0,x)); for(int i=1; i<=m; ++i) AE(read(),read(),read()); int cnt=Dijkstra(); Kruskal(n,cnt); for(int Q=read(); Q--; puts(Query()?"TAK":"NIE")); return 0; }