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
jjii子树内,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;
}
原文地址:https://www.cnblogs.com/xjqxjq/p/10544704.html