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

    最短路+最小生成树+倍增


      图论问题中综合性较强的一题= =(Orz vfk)

      比较容易发现,关键的还是有加油站的这些点,其他点都是打酱油的。

      也就是说我们重点是要求出 关键点之间的最短路

      这玩意……如果枚举加油站所在的点,然后跑单源最短路什么的……肯定TLE啊。

      我们记from[i]表示离 i 最近的关键点,仔细考虑一下,A->B的最短路径上,一定是前一半的from[i]为A,然后走过某条路以后,后一半的from[i]为B。为什么呢?我们不妨设中间出现了一个点x的from[x]=C,那么我们大可以从A走到C,加满油,再从C走到B,这样一定不会差!所以AB之间是否有边就看是否满足这样的条件了……

      做法是:先将所有关键点的dist置为0,丢到堆里面做dijkstra,求出每个点的dist和from,然后枚举每条边,如果它连接的两个点满足from[x]!=from[y],那么from[x]和from[y]这两个关键点之间的最短路就找到了。。。

      现在我们对只包含关键点的这张图做最小生成树,查询的时候倍增就可以了(又变成了货车运输。。。)

      小Trick:图可能不连通,考虑关键点的时候需要分连通块……我一开始光想着如果不在一个连通块内就为NIE,然而忘了既然是多个连通块,那就不能只dfs一次啊!!!

      1 /**************************************************************
      2     Problem: 4144
      3     User: Tunix
      4     Language: C++
      5     Result: Accepted
      6     Time:5076 ms
      7     Memory:51424 kb
      8 ****************************************************************/
      9  
     10 //BZOJ 4144
     11 #include<vector>
     12 #include<queue>
     13 #include<cstdio>
     14 #include<cstring>
     15 #include<cstdlib>
     16 #include<iostream>
     17 #include<algorithm>
     18 #define rep(i,n) for(int i=0;i<n;++i)
     19 #define F(i,j,n) for(int i=j;i<=n;++i)
     20 #define D(i,j,n) for(int i=j;i>=n;--i)
     21 using namespace std;
     22 typedef long long LL;
     23 inline int getint(){
     24     int r=1,v=0; char ch=getchar();
     25     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
     26     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
     27     return r*v;
     28 }
     29 const int N=2e5+10,INF=~0u>>1;
     30 /*******************template********************/
     31  
     32 int head[N],to[N<<1],nxt[N<<1],l[N<<1],cnt;
     33 void ins(int x,int y,int z){
     34     to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; l[cnt]=z;
     35 }
     36 struct edge{
     37     int x,y,w;
     38     bool operator < (const edge &b)const {return w<b.w;}
     39 }E[N<<1];
     40 int n,m,s,dis[N],from[N],c[N];
     41  
     42  
     43 int f[N],sz[N];
     44 inline int getf(int x){return f[x]==x?x:getf(f[x]);}
     45 typedef pair<int,int> pii;
     46 #define fi first
     47 #define se second
     48 #define mp make_pair
     49 priority_queue<pii,vector<pii>,greater<pii> >Q;
     50 bool vis[N];
     51 void dij(){
     52     F(i,1,n) dis[i]=INF;
     53     F(i,1,s){
     54         dis[c[i]]=0;
     55         from[c[i]]=c[i];
     56         Q.push(mp(0,c[i]));
     57     }
     58     while(!Q.empty()){
     59         int x=Q.top().se; Q.pop();
     60         if (vis[x]) continue;
     61         vis[x]=1;
     62         for(int i=head[x];i;i=nxt[i])
     63             if (dis[to[i]]>dis[x]+l[i]){
     64                 dis[to[i]]=dis[x]+l[i];
     65                 from[to[i]]=from[x];
     66                 Q.push(mp(dis[to[i]],to[i]));
     67             }
     68     }
     69     int tot=0;
     70     F(i,1,m){
     71         int x=to[i*2-1],y=to[i<<1];
     72         if (from[x]!=from[y])
     73             E[++tot]=(edge){from[x],from[y],dis[x]+dis[y]+l[i<<1]};
     74     }
     75     sort(E+1,E+tot+1);
     76     memset(head,0,sizeof head); cnt=0;
     77     F(i,1,n) f[i]=i,sz[i]=1;
     78     F(i,1,tot){
     79         int f1=getf(E[i].x),f2=getf(E[i].y);
     80         if (f1!=f2){
     81             if (sz[f1]>sz[f2]) swap(f1,f2);
     82             f[f1]=f2;
     83             sz[f2]+=sz[f1];
     84             ins(E[i].x,E[i].y,E[i].w);
     85             ins(E[i].y,E[i].x,E[i].w);
     86         }
     87     }
     88 }
     89  
     90 int fa[N][20],dep[N],mx[N][20],num,belong[N];
     91 void dfs(int x,int num){
     92     belong[x]=num;
     93     F(i,1,19)
     94         if (dep[x]>=(1<<i)){
     95             fa[x][i]=fa[fa[x][i-1]][i-1];
     96             mx[x][i]=max(mx[x][i-1],mx[fa[x][i-1]][i-1]);
     97         }else break;
     98     for(int i=head[x];i;i=nxt[i])
     99         if (to[i]!=fa[x][0]){
    100             fa[to[i]][0]=x;
    101             dep[to[i]]=dep[x]+1;
    102             mx[to[i]][0]=l[i];
    103             dfs(to[i],num);
    104         }
    105 }
    106 int query(int x,int y){
    107     if (dep[x]<dep[y]) swap(x,y);
    108     int t=dep[x]-dep[y],ans=0;
    109     F(i,0,19) if (t&(1<<i)) ans=max(ans,mx[x][i]),x=fa[x][i];
    110     D(i,19,0)
    111         if (fa[x][i]!=fa[y][i])
    112             ans=max(ans,max(mx[x][i],mx[y][i])),
    113             x=fa[x][i],y=fa[y][i];
    114     if (fa[x][0]!=fa[y][0]) return 0;
    115     if (x!=y) ans=max(ans,max(mx[x][0],mx[y][0]));
    116     return ans;
    117 }
    118 int main(){
    119 #ifndef ONLINE_JUDGE
    120     freopen("4144.in","r",stdin);
    121     freopen("4144.out","w",stdout);
    122 #endif 
    123     n=getint(); s=getint(); m=getint();
    124     F(i,1,s) c[i]=getint();
    125     F(i,1,m){
    126         int x=getint(),y=getint(),z=getint();
    127         ins(x,y,z); ins(y,x,z);
    128     }
    129     dij();
    130     memset(vis,0,sizeof vis);
    131     F(i,1,s) if (!belong[c[i]]) dfs(c[i],++num);
    132     int q=getint();
    133     while(q--){
    134         int x=getint(),y=getint(),z=getint();
    135         if (belong[x]!=belong[y]) puts("NIE");
    136         else puts((query(x,y)<=z) ? "TAK" : "NIE");
    137     }
    138     return 0;
    139 }
    View Code

    4144: [AMPPZ2014]Petrol

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 83  Solved: 36
    [Submit][Status][Discuss]

    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

    HINT

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    从1到n中找到任意num个数的和为sum的所有组合
    算法导论5.12
    使用c++技术实现下载网页
    算法导论5.13
    感慨
    算法导论2.37
    [转载]Yahoo!的分布式数据平台PNUTS简介及感悟
    Bigtable 论文笔记
    GFS 论文笔记
    MapReduce论文笔记
  • 原文地址:https://www.cnblogs.com/Tunix/p/4593049.html
Copyright © 2011-2022 走看看