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 }
  • 相关阅读:
    二分图模板(洛谷P3386)
    2013提高组复赛Day1
    2014Noip提高组复赛Day2题解
    Noip2016Day2T2 蚯蚓
    poj1655 Balancing Act
    codevs1919创世纪
    bzoj1040[ZJOI2008]骑士
    codevs1521 华丽的吊灯
    【20200414】ZumaV3-算法与数据结构课程作业
    【20171111】 Codevs 1214 线段覆盖
  • 原文地址:https://www.cnblogs.com/refun/p/10139116.html
Copyright © 2011-2022 走看看