链接
Description
给定一个n个点、m条边的带权无向图,其中有s个点是加油站。
每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油站可以补满。
q次询问,每次给出x,y,b,表示出发点是x,终点是y,油量上限为b,且保证x点和y点都是加油站,请回答能否从x走到y。
Input
第一行包含三个正整数n,s,m(2<=s<=n<=200000,1<=m<=200000),表示点数、加油站数和边数。
第二行包含s个互不相同的正整数c[1],c[2],…cs,表示每个加油站。
接下来m行,每行三个正整数u[i],v[i],di,表示u[i]和v[i]之间有一条长度为d[i]的双向边。
接下来一行包含一个正整数q(1<=q<=200000),表示询问数。
接下来q行,每行包含三个正整数x[i],y[i],bi,表示一个询问。
题解:
我不在赘述,直接引用大佬的
积累的思想,以图中k个关键点两两距离的最小生成树问题,只需跑多源最短路,每个点记录它最近的关键点,在枚举边连边
最后判联通可以离线,直接按b排序+并查集,比lca好写。主要是代码量少些。
虽然我的代码20min能够写完,但是在比赛中写这么多代码精力消耗会比较大,并且细节容易错
调题时一定不要想当然,比如当时就认为点不连通可以直接判掉,其实没有,对拍才发现,早就应该发现的
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define repd(i,a,b) for(int i=a;i>=b;--i)
#define rvc(i,S) for(int i=0;i<(int)S.size();++i)
#define fore(i,x) for(int i = head[x] ; i ; i = e[i].next)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define lowbit(x) (x&(-x))
using namespace std;
#define maxn 200020
#define inf INT_MAX
struct node{
int x,y,w;
bool operator < (node a)const{
return w < a.w;
}
}E[maxn * 2];
struct node2{
int next,to,w;
}e[maxn * 2],e2[maxn * 2];
int head[maxn],head2[maxn],cnt;
int fa[maxn],dis[maxn],q[maxn * 40],hh,tt,p[maxn],inq[maxn];
int n,m,T,s,tag[maxn],dth[maxn],jump[20][maxn],mx[20][maxn],tot,rt,vis[maxn],times;
inline void adde(int x,int y,int w){
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].w = w;
head[x] = cnt;
}
void spfa(){
while ( hh < tt ){
int x = q[hh++];
inq[x] = 0;
fore(i,x){
if ( dis[e[i].to] > dis[x] + e[i].w ){
dis[e[i].to] = dis[x] + e[i].w;
p[e[i].to] = p[x];
if ( !inq[e[i].to] ){
q[tt++] = e[i].to;
inq[e[i].to] = 1;
}
}
}
}
}
inline void adde2(int x,int y,int w);
int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }
void kruskal(){
rep(x,1,n){
fore(i,x){
if ( p[x] != p[e[i].to] )
E[++tot] = (node){p[x],p[e[i].to],dis[x] + dis[e[i].to] + e[i].w};
}
}
sort(E + 1,E + tot + 1);
rep(i,1,n) fa[i] = i;
cnt = 0;
rep(i,1,tot){
int x = E[i].x , y = E[i].y ,w = E[i].w;
int p = getfa(x) , q = getfa(y);
if ( p != q ){
fa[p] = q;
// cout<<x<<" "<<y<<" "<<w<<endl;
adde2(x,y,w) , adde2(y,x,w);
}
}
}
#define e e2
#define head head2
inline void adde2(int x,int y,int w){
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].w = w;
head[x] = cnt;
}
void dfs(int x){
vis[x] = times;
for(int i = head[x] ; i ; i = e[i].next){
if ( e[i].to == fa[x] ) continue;
fa[e[i].to] = jump[0][e[i].to] = x;
mx[0][e[i].to] = e[i].w;
dth[e[i].to] = dth[x] + 1;
dfs(e[i].to);
}
}
void init(){
rep(i,1,19)
rep(j,1,n){
jump[i][j] = jump[i - 1][jump[i - 1][j]];
mx[i][j] = max(mx[i - 1][j],mx[i - 1][jump[i - 1][j]]);
}
}
#undef e
#undef head
inline int getmx(int x,int y){
if ( dth[x] < dth[y] ) swap(x,y);
int d = dth[x] - dth[y],res = 0;
rep(i,0,19) if ( d & (1 << i) ) res = max(res,mx[i][x]) , x = jump[i][x];
if ( x == y ) return res;
repd(i,19,0) if ( jump[i][x] != jump[i][y] ){
res = max(res,max(mx[i][x],mx[i][y]));
x = jump[i][x], y = jump[i][y];
}
res = max(res,max(mx[0][x],mx[0][y]));
return res;
}
inline bool check(int x,int y,int b){
return getmx(x,y) <= b;
}
int main(){
freopen("input.txt","r",stdin);
scanf("%d %d %d",&n,&s,&m);
rep(i,1,n) dis[i] = inf;
rep(i,1,s){
int x;
scanf("%d",&x);
q[tt++] = x , dis[x] = 0 , p[x] = x , inq[x] = 1 , tag[x] = 1;
}
rep(i,1,m){
int x,y,w;
scanf("%d %d %d",&x,&y,&w);
adde(x,y,w) , adde(y,x,w);
}
spfa();
// rep(i,1,n) cout<<p[i]<<" "<<dis[i]<<endl;
kruskal();
rep(i,1,n) fa[i] = 0;
rep(i,1,n) if ( tag[i] && !fa[i] ){ ++times , dfs(i); }
init();
scanf("%d",&T);
while ( T-- ){
int x,y,b;
scanf("%d %d %d",&x,&y,&b);
if ( vis[x] == vis[y] && check(x,y,b) ) printf("TAK\n");
else printf("NIE\n");
}
}