• [USACO09JAN]安全出行Safe Travel



    最短路好题

    话说还有最短路树这种操作,以前没听说过

    题目要求我们求出从1到每个点不经过最短路的最后一条路的最短路径长度

    所以我们可以建出一棵最短路树

    考虑割掉一条边的最短路该怎么求

    如果我们要求Ans[i]

    那么就要找到一条非树边(因为能到达i的树边已经断了,只有非树边才能使图构成一个环)

    那么(Ans[i]=dis[u]+dis[v]+w(u,v)-dis[i])

    其中u是i的子树里的点,v必须不是i子树里的点

    这样u,v就可以更新从他们到LCA处的答案

    这样我们可以把所有非树边按照(dis[u]+dis[v]+w(u,v))排个序

    就可以直接从前往后更新答案了

    但是每个点只能更新一次(因为越早更新肯定越优)

    所以使用并查集来将更新过的点合并

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int M = 400005 ;
    using namespace std ;
    inline int read() {
        char c = getchar() ; int x = 0 , w = 1 ;
        while(c>'9'||c<'0') { if(c=='-') w= - 1 ; c = getchar() ; }
        while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
        return x*w ;
    }
    int n , m ;
    struct E { int Nxt , to , Dis , From ; }edge[M<<1] , b[M<<1] ;
    int hea[M] , num = 1 ;
    int fir[M] , fnum ;
    struct Node { int Id , Dis ; };
    priority_queue< Node > q ;
    bool vis[M] , Ist[M] ;
    int Dis[M] , fa[M] , Ans[M] , f[M] , dep[M] ;
    inline bool operator < (E a , E b) { return a.Dis < b.Dis ; }
    inline bool operator < (Node a , Node b) { return a.Dis > b.Dis ; }
    inline int Find(int x) { if(f[x] != x) f[x] = Find(f[x]) ; return f[x] ; }
    inline void add_edge(int from , int to , int Dis) {
        edge[++num].Nxt = hea[from] ; edge[num].to = to ; edge[num].From = from ;
        edge[num].Dis = Dis ; hea[from] = num ;
    }
    inline void Insert_edge(int from , int to , int Dis) {
        b[++fnum].Nxt = fir[from] ; b[fnum].to = to ; b[fnum].From = from ;
        b[fnum].Dis = Dis ; fir[from] = fnum ;
    }
    inline void Dijkstra(int S) {
        memset(Dis , 63 , sizeof(Dis)) ; Dis[S] = 0 ; q.push((Node){S , 0}) ;
        while(!q.empty()) {
        	int u = q.top().Id ; q.pop() ;
        	if(vis[u]) continue ; vis[u] = true ;
        	for(int i = hea[u] ; i ; i = edge[i].Nxt) {
        		int v = edge[i].to ;
        		if(Dis[v] > Dis[u] + edge[i].Dis) {
        			Dis[v] = Dis[u] + edge[i].Dis ; fa[v] = u ;
        			if(!vis[v]) q.push((Node){v , Dis[v]}) ;
                }
            }
        }
    }
    void Dfs(int u , int depth) {
        dep[u] = depth ;
        for(int i = hea[u] , v ; i ; i = edge[i].Nxt) {
            v = edge[i].to ; if(fa[v] != u) continue ;
            Ist[i] = Ist[i ^ 1] = true ; Dfs(v , depth + 1) ;
        }
    }
    inline void Re_Build() {
        for(int i = 2 , u , v ; i <= num ; i += 2) {
            if(!Ist[i]) {
                u = edge[i].From , v = edge[i].to ;
                Insert_edge(u , v , Dis[u] + Dis[v] + edge[i].Dis) ;
            }
        }
    }
    inline void Solve() {
        memset(Ans , -1 , sizeof(Ans)) ;
        sort(b + 1 , b + fnum + 1) ;
        for(int i = 1 ; i <= n ; i ++) f[i] = i ;
        for(int i = 1 , u , v , x , y ; i <= fnum ; i ++) {
            u = b[i].From , v = b[i].to ;
            x = Find(u) , y = Find(v) ;
            while(x != y) {
                if(dep[x] < dep[y]) swap(x , y) ;
                Ans[x] = b[i].Dis - Dis[x] ;
                f[x] = Find(fa[x]) ; x = Find(x) ;
            }
        }
    }
    int main() {
        n = read() ; m = read() ;
        for(int i = 1 , u , v , w ; i <= m ; i ++) {
            u = read() , v = read() , w = read() ;
            add_edge(u , v , w) ; add_edge(v , u , w) ;
        }
        Dijkstra(1) ; Dfs(1 , 1) ; Re_Build() ; Solve() ;
        for(int i = 2 ; i <= n ; i ++) printf("%d
    ",Ans[i]) ;
        return 0 ;
    }
    
    
  • 相关阅读:
    【第四章:互联寄生 上】静态时序分析圣经翻译计划
    【第三章:标准单元库 下】静态时序分析圣经翻译计划
    【第三章:标准单元库 中】静态时序分析圣经翻译计划
    【第三章:标准单元库 上】静态时序分析圣经翻译计划
    如何学习FPGA
    【第二章 STA概念 下】静态时序分析圣经翻译计划
    校招总结—FPGA从入门到放弃
    【第二章 STA概念 上】静态时序分析圣经翻译计划
    【第一章:绪论】静态时序分析圣经翻译计划
    frida-rpc调用
  • 原文地址:https://www.cnblogs.com/beretty/p/9609217.html
Copyright © 2020-2023  润新知