码迷,mamicode.com
首页 > 其他好文 > 详细

LuoguP1710 地铁涨价

时间:2018-10-27 22:33:47      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:--   names   return   方式   ==   code   std   register   void   

看到这个题,我们发现并不好维护删边。似乎我们删掉一条边,就得重建一次图。

那怎么避免这个呢。

我们可以删边的过程看做一个倒序加边的过程。

那么问题就转换成了:给定一个图,不断加边,求每个点到终点的最短路,成为最终图最短路的时间。

那么我们首先跑一遍最短路。然后重建图,倒序加边。

当一个点已经成为最短路点,那么入队(看是否可以松弛其他未成为路的点)。

可以发现,每个点至多被遍历一次,所以复杂度是可以接受的。

这种反向思维方式还是很有意思的。

#include <queue>
#include <string>
#include <cstdio>
#include <cstring>
#define RG register
#define Mkp make_pair
using namespace std;

inline int gi () {
    int x=0,w=0; char ch=0;
    while (!(ch>=0 && ch<=9)) ch=getchar ();
    while (ch>=0 && ch<=9) x=(x<<3)+(x<<1)+(ch^48), ch=getchar ();
    return w?-x:x;
}

const int N=1e5+10;
const int M=2e5+10;

priority_queue <pair <int,int> > que;
int tot,head[N],Next[M<<1],to[M<<1];
int n,m,q,cnt,u[M],v[M],vis[N],dis[N],ans[M],tag[N],qq[M],qur[M],Ans[M];

inline void Make (int from, int To) {
    Next[++tot]=head[from];
    head[from]=tot;
    to[tot]=To;
}

inline void Clear_ () {
    tot=0;
    memset (to, 0, sizeof (to));
    memset (head, 0, sizeof (head));
    memset (Next, 0, sizeof (Next));
}

void Dijkstra () {
    RG int i,x,y;
    memset (vis, 0, sizeof (vis));
    memset (dis, 0x3f, sizeof (dis));
    dis[1]=0; que.push (Mkp (0, 1));
    while (!que.empty ()) {
        x=que.top ().second; que.pop ();
        if (vis[x]) continue;
        vis[x]=1;
        for (i=head[x];i;i=Next[i]) {
            y=to[i];
            if (dis[y]>dis[x]+1) 
                dis[y]=dis[x]+1, que.push (Mkp (-dis[y], y));
        }           
    }
}

void DFS (int x, int fx) {
    RG int i,y;
    dis[x]=ans[fx]+1, tag[x]=0, cnt--;
    for (i=head[x];i;i=Next[i]) {
        y=to[i];
        if (y==fx) continue;
        if (ans[y]==dis[x]+1 && tag[y]) DFS (y, x);
    }
}

int main ()
{
    RG int i;
    n=gi (), m=gi (), q=gi ();
    for (i=1;i<=m;++i) {
        u[i]=gi (), v[i]=gi ();
        Make (u[i], v[i]), Make (v[i], u[i]);
    }
    Dijkstra (); Clear_ ();
    for (i=1;i<=n;++i) ans[i]=dis[i];
    for (i=1;i<=q;++i) qur[i]=gi (), qq[qur[i]]=1;
    for (i=1;i<=m;++i) {
        if (qq[i]) continue;
        Make (u[i], v[i]), Make (v[i], u[i]);
    }
    Dijkstra ();
    for (i=1;i<=n;++i)
        if (dis[i]>ans[i]) tag[i]=1, cnt++;
    for (i=q;i;--i) {
        Ans[i]=cnt;
        RG int a=u[qur[i]],b=v[qur[i]];
        if (ans[a]==dis[a] && dis[a]+1==ans[b] && tag[b]) DFS (b, a);
        if (ans[b]==dis[b] && dis[b]+1==ans[a] && tag[a]) DFS (a, b);
        Make (a, b), Make (b, a);
    }
    for (i=1;i<=q;++i) printf ("%d\n", Ans[i]);
    return 0;
}

 

LuoguP1710 地铁涨价

标签:--   names   return   方式   ==   code   std   register   void   

原文地址:https://www.cnblogs.com/Bhllx/p/9863696.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!