zoukankan      html  css  js  c++  java
  • BZOJ4144:[AMPPZ2014]Petrol(最短路,最小生成树)

    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],...c[s](1<=c[i]<=n),表示每个加油站。
    接下来m行,每行三个正整数u[i],v[i],d[i](1<=u[i],v[i]<=n,u[i]!=v[i],1<=d[i]<=10000),表示u[i]和v[i]之间有一条长度为d[i]的双向边。
    接下来一行包含一个正整数q(1<=q<=200000),表示询问数。
    接下来q行,每行包含三个正整数x[i],y[i],b[i](1<=x[i],y[i]<=n,x[i]!=y[i],1<=b[i]<=2*10^9),表示一个询问。

    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

    Solution

    $get$了一个新的小$trick$……话说为什么这么常用我之前竟然没有碰到过

    多源最短路,初始把多个点扔到堆/队列里,最后可以求出来每个点到最近的源点的距离。

    然后发现这个题,只有加油站那些点是有用的。然后我们就可以先跑一遍多源最短路,同时记录一下离每个点最近的加油站。

    将询问离然后求出加油站之间的最小生成树。加油站之间的边的边长也就是$dis[u]+dis[v]+w$,其中$w$是枚举的原图中每条边的边长。

    一遍往里加边一遍搞询问就好了……

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<queue>
     5 #include<algorithm>
     6 #define N (200009)
     7 using namespace std;
     8 
     9 struct Node
    10 {
    11     int num,dis;
    12     bool operator < (const Node &a) const {return dis>a.dis;}
    13 };
    14 struct Edge{int to,next,len;}edge[N<<1];
    15 struct E{int x,y,l;}L[N<<1];
    16 struct Que{int x,y,b,id;}Q[N];
    17 int n,s,m,u,v,l,cnt,t;
    18 int c[N],fa[N],dis[N],pre[N],vis[N],ans[N];
    19 int head[N],num_edge;
    20 priority_queue<Node>q;
    21 bool cmp1(E a,E b) {return a.l<b.l;}
    22 bool cmp2(Que a,Que b) {return a.b<b.b;}
    23 
    24 int Find(int x) {return x==fa[x]?x:fa[x]=Find(fa[x]);}
    25 
    26 void add(int u,int v,int l)
    27 {
    28     edge[++num_edge].to=v;
    29     edge[num_edge].next=head[u];
    30     edge[num_edge].len=l;
    31     head[u]=num_edge;
    32 }
    33 
    34 void Dijkstra()
    35 {
    36     memset(dis,0x7f,sizeof(dis));
    37     for (int i=1; i<=s; ++i)
    38     {
    39         dis[c[i]]=0; pre[c[i]]=c[i];
    40         q.push((Node){c[i],0});
    41     }
    42     while (!q.empty())
    43     {
    44         int x=q.top().num; q.pop();
    45         if (vis[x]) continue;
    46         vis[x]=true;
    47         for (int i=head[x]; i; i=edge[i].next)
    48             if (dis[x]+edge[i].len<dis[edge[i].to])
    49             {
    50                 dis[edge[i].to]=dis[x]+edge[i].len;
    51                 pre[edge[i].to]=pre[x];
    52                 q.push((Node){edge[i].to,dis[edge[i].to]});
    53             }
    54     }
    55 }
    56 
    57 void Kruskal()
    58 {
    59     for (int i=1; i<=n; ++i)
    60         for (int j=head[i]; j; j=edge[j].next)
    61             if (pre[i]!=pre[edge[j].to])
    62                 L[++cnt]=(E){pre[i],pre[edge[j].to],dis[i]+dis[edge[j].to]+edge[j].len};
    63     sort(L+1,L+cnt+1,cmp1);
    64     
    65     int now=1;
    66     for (int i=1; i<=n; ++i) fa[i]=i;
    67     for (int i=1; i<=t; ++i)
    68     {
    69         while(now<=cnt && L[now].l<=Q[i].b)
    70         {
    71             int fx=Find(L[now].x),fy=Find(L[now].y);
    72             if (fx!=fy) fa[fx]=fy; now++;
    73         }
    74         int fx=Find(Q[i].x),fy=Find(Q[i].y);
    75         if (fx==fy) ans[Q[i].id]=1;
    76         else ans[Q[i].id]=0;
    77     }
    78     for(int i=1;i<=t;i++)
    79         if(ans[i]) puts("TAK");
    80         else puts("NIE");
    81 }
    82 
    83 int main()
    84 {
    85     scanf("%d%d%d",&n,&s,&m);
    86     for (int i=1; i<=s; ++i)
    87         scanf("%d",&c[i]);
    88     for (int i=1; i<=m; ++i)
    89     {
    90         scanf("%d%d%d",&u,&v,&l);
    91         add(u,v,l); add(v,u,l);
    92     }
    93     Dijkstra();
    94     scanf("%d",&t);
    95     for (int i=1; i<=t; ++i)
    96         scanf("%d%d%d",&Q[i].x,&Q[i].y,&Q[i].b), Q[i].id=i;
    97     sort(Q+1,Q+t+1,cmp2);
    98     Kruskal();
    99 }
  • 相关阅读:
    OnEraseBkgnd、OnPaint与画面重绘
    .编译ADO类DLL时报错的解决方案
    VC列表框样式
    Codeforces 131D. Subway 寻找环树的最短路径
    Codeforces 103B. Cthulhu 寻找奈亚子
    Codeforces 246D. Colorful Graph
    Codeforces 278C. Learning Languages 图的遍历
    Codeforces 217A. Ice Skating 搜索
    Codeforces 107A. Dorm Water Supply 搜图
    Codeforces 263 D. Cycle in Graph 环
  • 原文地址:https://www.cnblogs.com/refun/p/10139116.html
Copyright © 2011-2022 走看看