• LuoguP1710 地铁涨价


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

    那怎么避免这个呢。

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

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

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

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

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

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

    #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
    ", Ans[i]);
        return 0;
    }
  • 相关阅读:
    js函数对象
    jQuery选择器
    js数组
    js知识点
    正则|数字|Format
    Ajax基础
    MVC 打包压缩
    JS(正则|JSON)
    CLR via C#
    Exists/In/Any/All/Contains操作符
  • 原文地址:https://www.cnblogs.com/Bhllx/p/9863696.html
Copyright © 2020-2023  润新知