zoukankan      html  css  js  c++  java
  • bzoj4144【AMPPZ2014】Petrol


    • 题解:

           首先注意到起点和终点都是加油站;

             假设中途经过某个非加油站的点u,u连到v,离u最近的加油站是x,那么从u到x加油后回到u,再到v一定不比直接从u到v差;

           因为u一定从某个加油站来,设最后经过的加油站为y,u点油量为B1 = b - dis(y,u),而如果u不可以走到x一定不能走到其他任何加油站自然也到不了终点,如果可以到x加满油也一定可以再从x回来,油量为B2 = b-dis(x,u)  , 因为dis(y,u) >= dis(x,u)所以B1 <= B2 ;

           考虑重新构图:nr[x]表示离x最近的加油站,dis[x]表示x和nr[x]的距离,可以用多源点dijkstra处理出所有nr[x]和dis[x];

           对于原图中边(u,v) 连边(nr[u] , nr[v] , dis[u] + dis[v] + w(u,v)   ) ;

           这就变成了一个图,只选<=b 的边问两点连通性,可以离线或者用kruskal重构树做;


     1 #include<bits/stdc++.h>
     2 #define mk make_pair
     3 #define fir first
     4 #define sec second 
     5 using namespace std;
     6 const int N=200010;
     7 int n,m,k,s,c[N],dis[N],nr[N],vis[N],fa[N],o,hd[N],cnt,ans[N];
     8 struct Edge{int u,v,nt,w;}E[N<<1],e[N],Q[N];
     9 void adde(int u,int v,int w){
    10     E[o]=(Edge){u,v,hd[u],w};hd[u]=o++;
    11     E[o]=(Edge){v,u,hd[v],w};hd[v]=o++;
    12 }
    13 typedef pair<int,int> pii;
    14 priority_queue<pii,vector<pii>,greater<pii> > q;
    15 void dijkstra(){
    16     memset(dis,0x3f,sizeof(dis));
    17     for(int i=1;i<=s;i++)q.push(mk(dis[c[i]]=0,c[i])),nr[c[i]]=c[i];
    18     while(!q.empty()){
    19         int u=q.top().sec;q.pop();
    20         if(vis[u])continue;
    21         vis[u]=1;
    22         for(int i=hd[u];~i;i=E[i].nt){
    23             int v=E[i].v;
    24             if(dis[v]>dis[u]+E[i].w){
    25                 dis[v]=dis[u]+E[i].w;
    26                 nr[v]=nr[u];
    27                 if(!vis[v])q.push(mk(dis[v],v)); 
    28             }
    29         }
    30     }
    31 }
    32 bool cmp(const Edge&A,const Edge&B){return A.w<B.w;}
    33 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    34 int main(){
    35     freopen("bzoj4144.in","r",stdin);
    36     freopen("bzoj4144.out","w",stdout);
    37     memset(hd,-1,sizeof(hd));
    38     scanf("%d%d%d",&n,&s,&m);
    39     for(int i=1;i<=s;i++)scanf("%d",&c[i]);
    40     for(int i=1;i<=m;i++){
    41         int u,v,w;
    42         scanf("%d%d%d",&u,&v,&w);
    43         adde(u,v,w);
    44     }
    45     scanf("%d",&k);
    46     for(int i=1;i<=k;i++){scanf("%d%d%d",&Q[i].u,&Q[i].v,&Q[i].w),Q[i].nt=i;}
    47     dijkstra();
    48     for(int i=0;i<o;i+=2){
    49         int u=E[i].u,v=E[i].v;
    50         if(nr[u]!=nr[v])e[++cnt]=(Edge){nr[u],nr[v],0,E[i].w+dis[u]+dis[v]};
    51     }
    52     for(int i=1;i<=n;i++)fa[i]=i;
    53     sort(e+1,e+cnt+1,cmp);
    54     sort(Q+1,Q+k+1,cmp);
    55     for(int i=1,j=1;i<=k;i++){
    56         while(j<=cnt&&e[j].w<=Q[i].w){
    57             int fx=find(e[j].u),fy=find(e[j].v);
    58             if(fx!=fy)fa[fx]=fy;
    59             j++;
    60         }
    61         ans[Q[i].nt] = find(Q[i].u)==find(Q[i].v);
    62     }
    63     for(int i=1;i<=k;i++){puts(ans[i]?"TAK":"NIE");}
    64     return 0;
    65 }
    bzoj4144
  • 相关阅读:
    python3学习之匿名函数
    python3学习之装饰器
    Linux服务器管理神器-IPython
    Linux 安装python3.4
    Linux一些常用操作命令
    Java并发知识分享
    LINUX 学习笔记 账号与群组的管理
    用JAVA写查询一个字符串中是否包含另外一个字符串以及出现的次数
    jQuery性能优化
    jQuery实用工具函数
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10204966.html
Copyright © 2011-2022 走看看