您的位置:首页 > 其它

bzoj 4144 [AMPPZ2014]Petrol 最短路+最小生成树+倍增

2016-11-10 15:05 399 查看
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,表示一个询问。

Output

输出q行。第i行输出第i个询问的答案,如果可行,则输出TAK,否则输出NIE。

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

很好的noip前复习题,顺带 练练看长代码的能力。

然后这题思路很简单:

容易观察出来 这是一个只跟加油站有关系的 故事。

所以呢 我们把 关键点之间的最短路建边

生成最小生成树

查询就是树上倍增,答案统计边权最大的。

ps 有个坑:就是图有可能不连通 所以 dfs不能只dfs一个点

上代码【今天我缩行了】【捂脸】【捂不住】

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
//by mars_ch
int n,s,m;
struct data{
int f,t,w,nxt;
}e[200005*2];
struct node{
int u,v,w;
}bian[200005*2];
struct orz{
int f,t,w,nxt;
}ee[200005*2];
int head[200005],tol;
int first[200005],tot;
queue<int> q;
int inq[200005],dis[200005],fa[200005],vis[200005],r[200005],p,cnt,root[200005],num,from[200005];
int deep[200005],f[200005][20],g[200005][20];
int find(int x){
if(fa[x] == x) return x;
return fa[x]=find(fa[x]);
}
bool cmp(node a,node b){
return a.w<b.w;
}
void add(int a,int b,int c){
e[tot].f=a,e[tot].t=b;
e[tot].w=c,e[tot].nxt=first[a];
first[a]=tot++;
}
void addd(int a,int b,int c){
ee[tol].f=a,ee[tol].t=b;
ee[tol].w=c,ee[tol].nxt=head[a];
head[a]=tol++;
}
void spfa(){
while(!q.empty()){
int u=q.front();
q.pop();
inq[u]=0;

for(int i=first[u];i!=-1;i=e[i].nxt){
int t=e[i].t;
if(dis[t]>dis[u]+e[i].w){
from[t]=from[u];
dis[t]=dis[u]+e[i].w;
if(!inq[t]){
inq[t]=1;
q.push(t);
}
}
}
}

}
void dfs(int x,int fat){
for(int i=1;i<=18;i++){
f[x][i]=f[f[x][i-1]][i-1];
g[x][i]=max(g[x][i-1],g[f[x][i-1]][i-1]);
}
for(int i=head[x];i!=-1;i=ee[i].nxt){
int t=ee[i].t;
if(t == fat) continue;
deep[t]=deep[x]+1;
f[t][0]=x,g[t][0]=ee[i].w;
dfs(t,x);
}
}
int lca(int x,int y){
int ans=0;
if(deep[x]<deep[y])swap(x,y);
for(int i=18;i!=-1;i--){
if(deep[x]-(1<<i)>=deep[y]){
ans=max(ans,g[x][i]);
x=f[x][i];
}
}
if(x==y)return ans;
for(int i=18;i!=-1;i--){
if(f[x][i]!=f[y][i]){
ans=max(ans,max(g[x][i],g[y][i]));
x=f[x][i],y=f[y][i];
}
}
return max(ans,max(g[x][0],g[y][0]));
}
int main()
{
scanf("%d%d%d",&n,&s,&m);
memset(first,-1,sizeof(first));
memset(head,-1,sizeof(head));
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=s;i++){
int a;
scanf("%d",&a);
from[a]=a;
dis[a]=0,inq[a]=1;
q.push(a);
}
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
spfa();
//printf("%d\n\n\n",from[4]);
for(int i=1;i<=m;i++)
{
int x=e[i*2-1].f,y=e[i*2-1].t;
if(from[x]!=from[y])
{
bian[++cnt].u=from[x],bian[cnt].v=from[y];
bian[cnt].w=dis[x]+dis[y]+e[i*2-1].w;
}
}
/*for(int i=1;i<=cnt;i++)
{
printf("%d %d %d\n",bian[i].u,bian[i].v,bian[i].w);
}*/
sort(bian+1,bian+cnt+1,cmp);
for(int i=1;i<=cnt;i++){
int fu=find(bian[i].u),fv=find(bian[i].v);
if(fu!=fv){
fa[fu]=fv;
addd(bian[i].u,bian[i].v,bian[i].w);
addd(bian[i].v,bian[i].u,bian[i].w);
}
}
for(int i=1;i<=n;i++){
if(dis[i] == 0){
if(!vis[find(i)]){
vis[find(i)]=1;
root[++num]=i;
}
}
}
for(int i=1;i<=num;i++){
dfs(root[i],-1);
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(find(x)!=find(y)) puts("NIE");
else if(z>=lca(x,y)) puts("TAK");
else puts("NIE");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: