• BZOJ3575 HNOI2014 道路阻塞


    3575: [Hnoi2014]道路堵塞

    Time Limit: 10 Sec  Memory Limit: 128 MB

    Description

    A国有N座城市,依次标为1到N。同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数。现在,A国交通部指定了一条从城市1到城市N的路径,并且保证这条路径的长度是所有从城市1到城市N的路径中最短的。不幸的是,因为从城市1到城市N旅行的人越来越多,这条由交通部指定的路径经常发生堵塞。现在A国想知道,这条路径中的任意一条道路无法通行时,由城市1到N的最短路径长度是多少。

    Input

    输入文件第一行是三个用空格分开的正整数N、M和L,分别表示城市数目、单向道路数目和交通部指定的最短路径包含多少条道路。
    按下来M行,每行三个用空格分开的整数a、b和c,表示存在一条由城市a到城市b的长度为c的单向道路。这M行的行号也是对应道路的编号,即其中第1行对应的道路编号为1,第2行对应的道路编号为2,…,第M行对应的道路编号为M。最后一行为L个用空格分开的整数sp(1)…,,sp(L),依次表示从城市1到城市N的由交通部指定的最短路径上的道路的编号。

    Output

    输出文件包含L行,每行为一个整数,第i行(i=1,2…,,L)的整数表示删去编号为sp(i)的道路后从城市1到城市N的最短路径长度。如果去掉后没有从城市1到城市N的路径,则输出一1。

    Sample Input

    4 5 2
    1 2 2
    1 3 2
    3 4 4
    3 2 1
    2 4 3
    1 5

    Sample Output

    6
    6

    HINT

    100%的数据满足2<N<100000,1<M<200000。所用道路长度大于0小于10000。
    数据已加强By Vfleaking

      你看见我的跳蚤国王了吗?哦它被FFF了?资磁!

      这题真是火的冒烟,劲爆无比,谁也想不到正解来自一个很扯淡的证明。

      正解:SPFA鬼畜技巧。

      因为它已经钦定了最短路,而且要对最短路上每一条边输出一次答案,所以很容易想到正解是枚举BAN哪条边再鬼一鬼。

      这里有个十分扯淡的证明:新·最短路一腚是S->之前最短路上某一点p->之前最短路上某一点q->T;

      感觉并不知道怎么证明是吧,但如果我说S和p,q和T 可以为同一个点呢?

      那么所有的情况都被包含了是的吗?没错是的。您强×把答案放在了一个鬼证明上。

      所以按照这个证明的思想,我们枚举删掉最短路上的哪条边,然后把这条边的s加进队列做SPFA。

      但是这样不加优化的做法会让你过吗?答案是显然否定的。那么来点更劲的:

      先把最短路上的所有边都BAN掉,然后从S到T开始恢复边,并把s丢进队列。

      然后每次就可以不清空dis数组了,因为你之前SPFA的结果你都可以调用以前的结果。

      然后统计答案就是把走到的钦定最短路上的点的距离加上它到T的距离取个min就好了。这里有一个玄妙的做法就是把答案加上这个点放成结构体扔进堆里,每次弹出到达点在s之前的点因为这是在这条路被BAN的时候SPFA到的,不一定是当前的合法方案,也不会比最优答案更好。所以判完-1后,第一个在s之后的点就不管是不是s更新的点了,却又是一个合法的点,就避免了很多麻烦。

      代码还是很好看懂的。

    #include    <iostream>
    #include    <cstdio>
    #include    <cstdlib>
    #include    <algorithm>
    #include    <vector>
    #include    <cstring>
    #include    <queue>
    #include    <complex>
    #include    <stack>
    #define LL long long int
    #define dob double
    using namespace std;
     
    const int N = 200010;
    struct Node{int from,to,val,next;}E[N];
    struct Data{int p,val;bool operator <(const Data &b)const{return val>b.val;}};
    int n,m,L,head[N],tot,ban[N],rk[N],In[N],far[N],dis[N],fr[N],s[N];
    queue<int>Q;priority_queue<Data>T;
     
    int gi()
    {
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
     
    inline void link(int u,int v,int c)
    {
      E[++tot]=(Node){u,v,c,head[u]};
      head[u]=tot;
    }
     
    inline void SPFA(int st)
    {
      queue<int>Q;Q.push(st);
      while(!Q.empty()){
        int x=Q.front();Q.pop();In[x]=0;
        for(int e=head[x];e;e=E[e].next){
          if(ban[e])continue;int y=E[e].to;
          if(far[x]+E[e].val<far[y]){
            far[y]=far[x]+E[e].val;
            if(fr[y])T.push((Data){fr[y],far[y]+dis[fr[y]]});
            else if(!In[y])Q.push(In[y]=y);
          }
        }
      }
    }
     
    int main()
    {
      n=gi();m=gi();L=gi();
      for(int i=1;i<=m;++i){
        int u=gi(),v=gi(),c=gi();
        link(u,v,c);
      }
      s[1]=1;fr[1]=1;
      for(int i=1;i<=L;++i){
        ban[rk[i]=gi()]=1;
        s[i+1]=E[rk[i]].to;
        fr[s[i+1]]=i+1;
      }
      for(int i=L;i;--i)
        dis[i]=dis[i+1]+E[rk[i]].val;
      memset(far,127/3,sizeof(far));far[1]=0;
      SPFA(1);
      for(int i=1;i<=L;++i){
        while(!T.empty() && T.top().p<=i)T.pop();
        if(T.empty())printf("-1
    ");
        else printf("%d
    ",T.top().val);
        far[E[rk[i]].to]=far[s[i]]+E[rk[i]].val;
        SPFA(s[i+1]);
      }
      return 0;
    }
    

      

      这还真TMD妙不可言,玄之又玄,精妙绝伦啊(伦boy:嗯?)。

  • 相关阅读:
    Codeforces Round #251 (Div. 2) A
    topcoder SRM 623 DIV2 CatAndRat
    topcoder SRM 623 DIV2 CatchTheBeatEasy
    topcoder SRM 622 DIV2 FibonacciDiv2
    topcoder SRM 622 DIV2 BoxesDiv2
    Leetcode Linked List Cycle II
    leetcode Linked List Cycle
    Leetcode Search Insert Position
    关于vim插件
    Codeforces Round #248 (Div. 2) B. Kuriyama Mirai's Stones
  • 原文地址:https://www.cnblogs.com/fenghaoran/p/7219995.html
Copyright © 2020-2023  润新知