1972: 最短路(shortest)
阿新 • • 發佈:2018-12-20
題目描述
給出一個n個點m條邊的無向圖,n個點的編號從1~n,定義源點為1。定義最短路樹如下:從源點1經過邊集T到任意一點i有且僅有一條路徑,且這條路徑是整個圖1到i的最短路徑,邊集T構成最短路樹。 給出最短路樹,求對於除了源點1外的每個點i,求最短路,要求不經過給出的最短路樹上的1到i的路徑的最後一條邊。
題解
設表示第個點到根的路徑和 一個點在不向上走一步的情況下,應該是在其子樹內找到一個點,走到那然後通過一條非樹邊走出這棵子樹,然後走到根更優 即第個點的答案應為 (在子樹內,在子樹外) 考慮最小化,即每條非樹邊造成的影響 對於一條非樹邊,它所能影響到的點在以及的路徑上且不包括 所以樹剖,以樹剖序建線段樹,然後區間更新最小值即可 效率 (有更好的方法,利用並查集,效率為)
#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; }