题意:
给定一个n个点、m条边的带权无向图,其中有s个点是加油站。
每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油站可以补满。
q次询问,每次给出x,y,b,表示出发点是x,终点是y,油量上限为b,且保证x点和y点都是加油站,请回答能否从x走到y。
题解:
关键是要求出加油站之间的最小生成树,然后倍增求最大值。
用类似bzoj 4242的方法即可。
各种sb错误调了很久
code:
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL inf=(1LL<<60);
struct node{
int x,y,next;
LL c;
}a[400010],b[200010];int len=0,last[200010];
int n,s,m,fa[200010];
struct P{
int x;LL dis;
P() {}
P(int a,LL b) {x=a;dis=b;}
};
struct trnode{
int fa[21],dep;
LL c[21];
}tr[200010];
bool operator < (P a,P b) {return a.dis>b.dis;}
priority_queue<P> q;
int belong[200010];
LL dis[200010];
bool vis[200010];
int findfa(int x) {return fa[x]==x?x:fa[x]=findfa(fa[x]);}
void ins(int x,int y,LL c)
{
a[++len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
}
void dij()
{
while(!q.empty())
{
P t=q.top();q.pop();int x=t.x;
if(vis[x]) continue;
vis[x]=true;
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(dis[x]+(LL)a[i].c<dis[y])
{
dis[y]=dis[x]+(LL)a[i].c;belong[y]=belong[x];
q.push(P(y,dis[y]));
}
else
if(vis[y]) b[++len].x=belong[x],b[len].y=belong[y],b[len].c=(LL)(dis[x]+dis[y]+a[i].c);
}
}
}
void dfs(int x,int fa,LL c)
{
tr[x].dep=tr[fa].dep+1;tr[x].fa[0]=fa;tr[x].c[0]=c;
vis[x]=true;
for(int i=1;(1<<i)<=tr[x].dep;i++)
{
tr[x].fa[i]=tr[tr[x].fa[i-1]].fa[i-1];
tr[x].c[i]=max(tr[x].c[i-1],tr[tr[x].fa[i-1]].c[i-1]);
}
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
dfs(y,x,a[i].c);
}
}
LL findans(int x,int y)
{
LL ans=0;
if(tr[x].dep<tr[y].dep) swap(x,y);
for(int i=19;i>=0;i--)
if((1<<i)<=tr[x].dep-tr[y].dep)
{
ans=max(ans,tr[x].c[i]);
x=tr[x].fa[i];
}
if(x==y) return ans;
for(int i=19;i>=0;i--)
if((1<<i)<=tr[x].dep&&tr[x].fa[i]!=tr[y].fa[i])
{
ans=max(ans,tr[x].c[i]);ans=max(ans,tr[y].c[i]);
x=tr[x].fa[i];y=tr[y].fa[i];
}
ans=max(ans,tr[x].c[0]);ans=max(ans,tr[y].c[0]);
return ans;
}
bool cmp(node a,node b) {return a.c<b.c;}
int main()
{
scanf("%d %d %d",&n,&s,&m);
for(int i=1;i<=n;i++) dis[i]=inf;
memset(vis,false,sizeof(vis));
for(int i=1;i<=s;i++)
{
int k;scanf("%d",&k);
belong[k]=k;
dis[k]=0;q.push(P(k,0LL));
}
for(int i=1;i<=m;i++)
{
int x,y;LL c;scanf("%d %d %lld",&x,&y,&c);
ins(x,y,c);ins(y,x,c);
}
len=0;dij();
int m=len;memset(last,0,sizeof(last));
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++) fa[i]=i;
sort(b+1,b+m+1,cmp);len=0;
for(int i=1;i<=m;i++)
{
int x=findfa(b[i].x),y=findfa(b[i].y);
if(x!=y)
{
ins(x,y,b[i].c),ins(y,x,b[i].c);
fa[x]=y;
}
}
tr[0].dep=-1;for(int i=1;i<=n;i++) if(belong[i]==i&&!vis[i]) dfs(i,0,inf);
int Q;scanf("%d",&Q);
while(Q--)
{
int x,y;LL B,t;scanf("%d %d %lld",&x,&y,&B);t=findans(x,y);
if(B>=t) printf("TAK\n");
else printf("NIE\n");
}
}