P2934 [USACO09JAN]Safe Travel G 题解
P2934 [USACO09JAN] Safe Travel G
更好体验
题目
考点:最短路树 & 并查集缩点
正式开始讲解
题意:求在不经过原来
样例的图画出来是这样:
既然最短路唯一,我们可以记录
由样例构造出的最短路树是这样的:
红色边为最短路树上的边,黑色边不属于最短路树,我们将不属于最短路树的边称为非树边。为了方便,我们把树边标记为红色,非树边为黑色。
题目求的路径,也就是在不经过最短路树上
很显然,如果每次都断开边重构最短路树的话,本质上就是跑了
根据最短路树的性质,在断开
因此,断开边后,树上路径-->非树边-->树上路径 的形式。
我们做如下定义:
那么我们不妨换一个角度,枚举每一条非树边,考虑有哪些节点到源点的“最好路径”可能经过这条边。经过一些考虑,我们发现,对于边
因此,对于每个点
因为
所以,如果将非树边
时间复杂度:
Code
删除上一条边后如果
翻译这道题的人漏了好多要素
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pr;
int n,m;
struct edge{
int v;
ll w;
edge(){} edge(int v_,ll w_){ v=v_,w=w_; }
};
vector<edge> e[100005];
ll d[100005];
int fa[100005][30],dep[100005];
priority_queue<pr> q;
void dijkstra(){
while(!q.empty()){ q.pop(); }
for(int i=1;i<=n;i++){ d[i]=-1; }
d[1]=0;q.push(make_pair(0,1));
while(!q.empty()){
pr nw=q.top();q.pop();
int u=nw.second;
for(int i=e[u].size()-1;i>=0;i--){
int v=e[u][i].v;
ll w=e[u][i].w;
if(d[v]==-1 || d[v]>d[u]+w){
d[v]=d[u]+w;
fa[v][0]=u;
dep[v]=dep[u]+1;
q.push(make_pair(-d[v],v));
}
}
}
}
void init(){
for(int j=1;j<=25;j++){
for(int i=1;i<=n;i++){
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
}
int lca(int u,int v){
if(dep[v]>dep[u]){
swap(u,v);
}
for(int i=25;i>=0;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
for(int i=25;i>=0;i--) if(fa[u][i]!=fa[v][i]){ u=fa[u][i];v=fa[v][i]; }
return fa[u][0];
}
struct nont{
int u,v;
ll w;
nont(){} nont(int u_,int v_,ll w_){ u=u_,v=v_,w=w_; }
};
bool operator<(nont a,nont b){
return d[a.u]+d[a.v]+a.w < d[b.u]+d[b.v]+b.w;
}
nont nt[200005];int tp=0;
ll ans[100005];
int nx[100005];
int getfa(int u){
return (u==nx[u])?u:(nx[u]=getfa(nx[u]));
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b;ll t;
scanf("%d%d%lld",&a,&b,&t);
e[a].push_back(edge(b,t));
e[b].push_back(edge(a,t));
}
dijkstra();
init();
for(int i=1;i<=n;i++){
ans[i]=-1; // 没有满足条件路径一定要输出 -1 否则 100Pts -> 40Pts
nx[i]=i;
for(int j=e[i].size()-1;j>=0;j--){
int u=i,v=e[i][j].v;
ll w=e[i][j].w;
if(fa[v][0]!=u && fa[u][0]!=v && u<v){
nt[++tp]=nont(u,v,w);
}
}
}
sort(nt+1,nt+tp+1);
for(int i=1;i<=tp;i++){
int x=nt[i].u,y=nt[i].v;
ll kw=d[x]+d[y]+nt[i].w;
int u=getfa(x),v=getfa(y);
while(u!=v){
if(dep[u]<dep[v]){
swap(u,v);
}
ans[u]=kw-d[u];
nx[u]=fa[u][0];
u=getfa(u);
}
}
for(int i=2;i<=n;i++){
printf("%lld\n",ans[i]);
}
return 0;
}