题意
N
点
题解
我们暂且称避开最短路最后一条边的路径为“次短路”(不是真正的次短路)。
首先将最短路经过的最后一条边都求出来,这些边将形成一棵以1为根的树。
考虑到达点u的答案。若避开点u与fa[u]中的这条边,那么次短路必然是从点1经过最短路到达某点v,从v经过非树边到达点w,从点w沿着最短路向根的方向找到u(即w为u-子树中的节点)。
如图,图(1)中是一种合法的情况,而图(2)中v与w都在u的子树中,这显然是不合法的。即对于所有的非树边的两个端点,若有且仅有一个端点在u的子树中(包含u)就能更新u的答案。如果这样,每个点u都可以由一个非树边的集合来更新它,如果枚举肯定不能接受。观察一条非树边[v,w]如何更新u的答案:
ans[u]=dis[v]+len[v,w]+dis[w]−dis[u]
ans[u]−dis[u]=dis[v]+len[v,w]+dis[w]
我们最小化 dis[v]+len[v,w]+dis[w] 就可最小化ans[u],于是很容易想到用堆维护这个边集,再自下而上地合并堆,这样就可以由下而上得到每个点的非树边边集。每次更新时将端点不满足有且仅有一个在子树中的非树边都删掉。
如果进行堆的合并,优先队列是 O(n) 的,而左偏树是 O(logn) 的,所以选择左偏树编写。
代码
/// by ztx
/// blog.csdn.net/hzoi_ztx
#include <bits/stdc++.h>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v) for(i=v.begin();i!=v.end();i++)
#define r(x) read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
struct ltnode {
int w, u, v;
bool operator < (const ltnode&B) const { return w > B.w; }
};
struct lt {
lt *l, *r;
int d;
ltnode w;
lt();
lt(ltnode w);
}*null=new lt();
lt::lt() { l=r=null;d=0; }
lt::lt(ltnode w): w(w) { l=r=null;d=0; }
lt* Init(ltnode x) { return new lt(x); }
lt* Merge(lt*u,lt*v) {
if (u == null) return v;
if (v == null) return u;
if (u->w < v->w) std::swap(u,v);
u->r = Merge(u->r,v);
if (u->l->d < u->r->d) std::swap(u->l,u->r);
u->d = u->r->d+1;
return u;
}
void Insert(lt*&u,ltnode x) { u = Merge(u,Init(x)); }
ltnode Top(lt*u) { return u->w; }
void Pop(lt*&u) { lt*tmp = u; u = Merge(u->l,u->r); delete tmp; }
bool Empty(lt*u) { return u == null; }
#define kN 100010LL
#define kM 200010LL
#define infi 0x3f3f3f3fLL
#define t(p) to[p]
#define l(p) len[p]
#define n(p) nxt[p]
#define s(u) st[u]
int to[kM<<1], len[kM<<1], nxt[kM<<1], st[kN], te = 1;
inline void Add(int u,int v,int w) {
te++;t(te)=v;l(te)=w;n(te)=s(u);s(u)=te;
te++;t(te)=u;l(te)=w;n(te)=s(v);s(v)=te;
}
int dis[kN], pre[kN];
bool inq[kN];
std::deque<int>q;
inline void spfa() {
int u, v, p;
memset(dis,0x3f,sizeof dis);
q.push_back(1), dis[1] = 0;
while (!q.empty())
for (u=q.front(),q.pop_front(),inq[u]=false,p=s(u);p;p=n(p))
if (v=t(p),dis[v]>dis[u]+l(p))
if (dis[v]=dis[u]+l(p),pre[v]=u,!inq[v])
if (inq[v]=true,!q.empty()&&dis[v]<dis[q.front()])q.push_front(v);
else q.push_back(v);
}
int n, m, a[kM], b[kM], t[kM];
int ans[kN], fa[kN];
std::vector<int>g[kN];
lt *h[kN];
inline int anc(int u) { return fa[u]?fa[u]=anc(fa[u]):u; }
void Union(int u,int v) { if((u=anc(u))!=(v=anc(v)))fa[u]=v; }
void dp(int u) {
for (int i=g[u].size()-1;i>=0;i--) {
dp(g[u][i]);
h[u] = Merge(h[u],h[g[u][i]]);
Union(u,g[u][i]);
}
while (!Empty(h[u]) && anc(Top(h[u]).u)==anc(Top(h[u]).v)) Pop(h[u]);
if (Empty(h[u])) ans[u] = -1;
else ans[u] = Top(h[u]).w-dis[u];
}
int main() {
int i;
r(n), r(m);
Rep (i,1,m) r(a[i]), r(b[i]), r(t[i]), Add(a[i],b[i],t[i]);
spfa();
Rep (i,1,n) g[pre[i]].push_back(i), h[i] = null;
Rep (i,1,m) {
if (pre[a[i]]==b[i] || pre[b[i]]==a[i]) continue;
Insert(h[a[i]],(ltnode){dis[a[i]]+dis[b[i]]+t[i],a[i],b[i]});
Insert(h[b[i]],(ltnode){dis[a[i]]+dis[b[i]]+t[i],a[i],b[i]});
}
dp(1);
Rep (i,2,n) printf("%d\n", ans[i]);
END: getchar(), getchar();
return 0;
}