zoukankan      html  css  js  c++  java
  • 曾有两次 [最短路树]

    曾有两次


    color{red}{正解部分}

    11 号节点 为 根节点 建立 最短路树, 一个节点删边时一定是删去 父边,
    考虑 删去父边后当前节点 uu11 的最短路长是什么,

    一定是 uu v w1u ightarrow u子树内节点 v -^{非树边} ightarrow w ightarrow 1,
    最短路长为 depsvdepsu+W+depswdeps_v-deps_u+W_{非树边}+deps_w,

    于是考虑使用 树链剖分线段树 维护 depsv+depsw+Wdeps_v+deps_w+W_{非树边}最小值 minnminn, minndepsuminn - deps_u 即为答案 .

    非树边 vwv ightarrow w 作用的范围为 uuvv树上路径 上的点 (除 lcalca), 如下图所示黄色部分,


    color{red}{实现部分}

    • 注意重边, 自环 .
    #include<bits/stdc++.h>
    #define reg register
    #define se second
    typedef long long ll;
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const ll inf = 1e17 + 5;
    const int maxn = 1e6 + 10;
    
    int N;
    int M;
    int num0;
    int Tmp_1;
    int dfs_tim;
    int Mp[maxn];
    int Fe[maxn];
    int Fk[maxn];
    int top[maxn];
    int dep[maxn];
    int dfn[maxn];
    int son[maxn];
    int head[maxn];
    int size[maxn];
    
    ll Dis[maxn];
    
    bool vis[maxn];
    
    struct Edge{ int nxt, to, w; } edge[maxn << 1], E[maxn];
    
    void Add(int from, int to, int w){ edge[++ num0] = (Edge){ head[from], to, w }; head[from] = num0; }
    
    struct Segment_Tree{
    
            struct Node{ int l, r; ll min_v, tg; } T[maxn << 2];
    
            void Push_down(const int &k){
                    T[k].min_v = std::min(T[k].min_v, T[k].tg);
                    if(T[k].l == T[k].r) return T[k].tg=inf, void();
                    T[k<<1].tg = std::min(T[k<<1].tg, T[k].tg), T[k<<1|1].tg = std::min(T[k<<1|1].tg, T[k].tg);
                    T[k].tg = inf;
            }
    
            void Push_up(const int &k){
                    if(T[k<<1].tg != inf) Push_down(k<<1);
                    if(T[k<<1|1].tg != inf) Push_down(k<<1|1);
                    T[k].min_v = std::min(T[k<<1].min_v, T[k<<1|1].min_v);
            }
    
            void Build(int k, int l, int r){
                    T[k].l = l, T[k].r = r, T[k].min_v = T[k].tg = inf;
                    if(l == r) return ;
                    int mid = l+r >> 1; Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
            }
    
            void Modify(int k, const int &ql, const int &qr, const ll &aim){
                    int l = T[k].l, r = T[k].r;
                    if(T[k].tg != inf) Push_down(k);
                    if(r < ql || l > qr) return ;
                    if(ql <= l && r <= qr){ T[k].tg = std::min(T[k].tg, aim); Push_down(k); return ; }
                    Modify(k<<1, ql, qr, aim), Modify(k<<1|1, ql, qr, aim); Push_up(k);
            }
    
            ll Query(int k, const int &ql, const int &qr){
                    int l = T[k].l, r = T[k].r; 
                    if(T[k].tg != inf) Push_down(k);
                    if(r < ql || l > qr) return inf;
                    if(ql <= l && r <= qr) return T[k].min_v;
                    return std::min(Query(k<<1, ql, qr), Query(k<<1|1, ql, qr));
            }
    
    } seg_t;
    
    void Dij(){
            typedef std::pair<ll, int> pr;
            std::priority_queue <pr, std::vector<pr>, std::greater<pr> > Q;
            for(reg int i = 2; i <= N; i ++) Dis[i] = inf; Q.push(pr(0, 1));
            while(!Q.empty()){
                    int ft = Q.top().se; Q.pop();
                    if(vis[ft]) continue ; vis[ft] = 1;
                    for(reg int i = head[ft]; i; i = edge[i].nxt){
                            int to = edge[i].to;
                            if(Dis[to] > Dis[ft] + edge[i].w){
                                    Fk[to] = ft, Fe[to] = Mp[i];
                                    Dis[to] = Dis[ft] + edge[i].w;
                                    Q.push(pr(Dis[to], to));
                            }
                    }
            }
            num0 = 1;
            for(reg int i = 1; i <= N; i ++) head[i] = vis[i] = 0;
            for(reg int i = 2; i <= N; i ++) Add(Fk[i], i, E[Fe[i]].w), Add(i, Fk[i], E[Fe[i]].w), vis[Fe[i]] = 1;
    }
    
    void DFS_1(int k, int fa){
            size[k] = 1, dep[k] = dep[fa] + 1;
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ;
                    DFS_1(to, k); size[k] += size[to];
                    if(size[to] > size[son[k]]) son[k] = to;
            }
    }
    
    void DFS_2(int k, int tp){
            top[k] = tp, dfn[k] = ++ dfs_tim;
            if(son[k]) DFS_2(son[k], tp);
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == son[k] || to == Fk[k]) continue ;
                    DFS_2(to, to);
            }
    }
    
    void Modify(int x, int y, ll d){
            while(top[x] != top[y]){
                    if(dep[top[x]] < dep[top[y]]) std::swap(x, y);
                    seg_t.Modify(1, dfn[top[x]], dfn[x], d);
                    x = Fk[top[x]];
            } 
            if(dfn[x] < dfn[y]) std::swap(x, y);
            if(dfn[y]+1 > dfn[x]) return ;
            seg_t.Modify(1, dfn[y]+1, dfn[x], d);
    }
    
    int main(){
            read(); N = read(); M = read();
            seg_t.Build(1, 1, N); Tmp_1 = 0;
            num0 = 1;
            for(reg int i = 1; i <= M; i ++){
                    int u = read(), v = read(), w = read();
                    if(u == v) continue ;
                    Add(u, v, w), Add(v, u, w);
                    E[++ Tmp_1] = (Edge){ u, v, w };
                    Mp[num0] = Mp[num0^1] = Tmp_1;
            }
            M = Tmp_1; Dij(); DFS_1(1, 0); DFS_2(1, 1);
            for(reg int i = 1; i <= Tmp_1; i ++){
                    if(vis[i]) continue ;
                    int u = E[i].nxt, v = E[i].to;
                    Modify(u, v, Dis[u] + Dis[v] + E[i].w);
            }
            printf("0 ");
            for(reg int i = 2; i <= N; i ++){
                    ll min_d = seg_t.Query(1, dfn[i], dfn[i]);
                    if(min_d == inf) min_d = -1;
                    else min_d -= Dis[i];
                    printf("%lld ", min_d);
            }
            return 0;
    }
    
  • 相关阅读:
    java面向对象下:Java数据库编程
    异常处理小结
    drupal进入不了后台时候的解决办法,作者使用drush方案,已验证
    背后的幽灵“美国”
    2016第30周六
    2016第30周五
    Java 网络I/O模型
    2016第30周三-流媒体部分概念
    2016第30周二
    JS冲突解决方法
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822419.html
Copyright © 2011-2022 走看看