1. 程式人生 > >1972: 最短路(shortest)

1972: 最短路(shortest)

題目描述

給出一個n個點m條邊的無向圖,n個點的編號從1~n,定義源點為1。定義最短路樹如下:從源點1經過邊集T到任意一點i有且僅有一條路徑,且這條路徑是整個圖1到i的最短路徑,邊集T構成最短路樹。 給出最短路樹,求對於除了源點1外的每個點i,求最短路,要求不經過給出的最短路樹上的1到i的路徑的最後一條邊。

題解

did_i表示第ii個點到根的路徑和 一個點在不向上走一步的情況下,應該是在其子樹內找到一個點,走到那然後通過一條非樹邊走出這棵子樹,然後走到根更優 即第ii個點的答案應為djdi+lenj,k+dkd_j-d_i+len_{j,k}+d_k

+dkjjii子樹內,kkii子樹外) 考慮最小化dj+lenj,k+dkd_j+len_{j,k}+d_k,即每條非樹邊造成的影響 對於一條非樹邊(j,k)(j,k),它所能影響到的點在j>lcaj->lca以及k>lcak->lca的路徑上且不包括lcalca 所以樹剖,以樹剖序建線段樹,然後區間更新最小值即可 效率O(nlog2n)O(nlog^2n) (有更好的方法,利用並查集,效率為O(nlogn)O(nlogn)

#include <cstdio>
#include <algorithm>
#include <cstring>
#define Ls k<<1
#define Rs Ls|1
#define F 0x3f3f3f3f
#define I inline
#define E register
using namespace std;
const int N=4005;struct O{int u,v,w;}p[100005];
int n,m,c,t,head[N],V[N*2],nex[N*2],W[N*2],d[N],fa[N];
int dep[N],top[N],sz[N],son[N],id[N],tt,a[N*4],dfn[N],s[N];
I void add(E int u,E int v,E int w){
    V[++t]=v;nex[t]=head[u];head[u]=t;W[t]=w;
}
I void dfs1(E int x,E int fat,E int deep){
    fa[x]=fat;dep[x]=deep;sz[x]=1;
    for (E int i=head[x];i;i=nex[i]){
        if (V[i]==fat) continue;
        d[V[i]]=d[x]+W[i];
        dfs1(V[i],x,deep+1);
        sz[x]+=sz[V[i]];
        if (sz[V[i]]>sz[son[x]])
            son[x]=V[i];
    }
}
I void dfs2(E int x,E int tp){
    top[x]=tp;id[x]=++tt;dfn[tt]=x;
    if (son[x]) dfs2(son[x],tp);
    for (E int i=head[x];i;i=nex[i])
        if (V[i]^son[x] && V[i]^fa[x])
            dfs2(V[i],V[i]);
}
I void query(E int k,E int l,E int r,E int w){
    if (l==r){s[dfn[l]]=min(w,a[k]);return;}
    E int mid=l+r>>1;
    query(Ls,l,mid,min(a[k],w));
    query(Rs,mid+1,r,min(a[k],w));
}
I void update(E int k,E int l,E int r,E int L,E int R,E int w){
    if (L<=l && r<=R){a[k]=min(a[k],w);return;}
    E int mid=l+r>>1;
    if (mid>=L) update(Ls,l,mid,L,R,w);
    if (mid<R) update(Rs,mid+1,r,L,R,w);
}
I void update_chain(E int x,E int y,E int w){
    while(top[x]^top[y]){
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,1,n,id[top[x]],id[x],w);x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y);
    update(1,1,n,id[x]+1,id[y],w);
}
int main(){
    scanf("%d%d",&n,&m);memset(a,F,sizeof a);
    for (E int u,v,w,ty,i=1;i<=m;i++){
        scanf("%d%d%d%d",&u,&v,&w,&ty);
        if (ty) add(u,v,w),add(v,u,w);
        else p[++c]=(O){u,v,w};
    }
    dfs1(1,0,1);dfs2(1,1);
    for (E int i=1;i<=c;i++)
        update_chain(p[i].u,p[i].v,d[p[i].u]+d[p[i].v]+p[i].w);
    query(1,1,n,F);
    for (E int i=2;i<=n;i++)
        if (s[i]==F) puts("-1");
        else printf("%d ",s[i]-d[i]);
    return 0;
}