P2934 [USACO09JAN] Safe Travel G
题目大意
给定一张有 \(n\) 个节点,\(m\) 条边的无向图,对于任意的 \(i\)(\(2\le i\le n\)),请求出在不经过原来 \(1\) 节点到 \(i\) 节点最短路上最后一条边的前提下,\(1\) 节点到 \(i\) 节点的最短路。满足每一个点只对应一条最短路。
\(n\leq 10^5,m\leq 2\times 10^5\)
思路
考虑对于这个图现求出最短路,之后建一个最短路树。不妨设这棵树上节点 \(u\) 的父亲为 \(f_u\),\(1\) 到 \(u\) 的最短路长度为 \(d_i\)。则对于本题我们要求的是在树上删掉 \(f_u\) 到 \(u\) 这条边后通过树外的一条边获得的最小最短路。
之后我们设选择一条树外的边 \((x,y)\),。其中因为 \(u\) 到不了 \(f_u\),即到不了 \(1\)。所以我们只能从 \(u\) 的子树走到不在 \(u\) 的子树内的另一个点。不妨设 \(y\) 在子树内,\(x\) 在子树外。所以我们要选择一对 \((x,y)\) 使得 \(d_x+d_y+w_{(x,y)}-d_u\) 最小,其中 \(w_{(x,y)}\) 表示 \((x,y)\) 这条边的边权。这个式子简单画一画就能看懂。
所以不妨将所有树外的边按照上面的式子从小到大排序,这样每一次更新后的元素就不用再更新了。所以我们用并查集去维护树上每一个节点是否遍历过,然后就可以快速跳过。这样每一个节点最多被更新一次。
之后我们考虑每条树外的边 \((x,y)\) 能更新哪些节点。因为 \(y\) 在子树内,\(x\) 在子树外,所以我们能更新到 \(x,y\) 的最近公共祖先,且不能更新这个最近公共祖先,因为从这个节点(包括它)以后的所有节点被更新时 \(x,y\) 都在同一个子树内了,不符合题意。
之后就做完了。
代码
#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
const ll MAXN=1e6+5;
ll dis[MAXN];
struct edge{
ll id,u,v,w;
bool operator<(const edge&K)const{
return dis[u]+dis[v]+w<dis[K.u]+dis[K.v]+K.w;
}
};
vector<edge>adj[MAXN],e,E;
bool vis[MAXN];
ll fe[MAXN];
void dijkstra(){
memset(dis,0x3f,sizeof(dis));
priority_queue<pair<ll,ll>,vector<pair<ll,ll>>,greater<>>q;
dis[1]=0;
q.push({0,1});
while(!q.empty()){
ll u=q.top().second;
q.pop();
if(vis[u]){
continue;
}
vis[u]=true;
for(auto i:adj[u]){
ll v=i.v,w=i.w;
if(dis[v]>dis[u]+w){
fe[v]=i.id;
dis[v]=dis[u]+w;
q.push({dis[v],v});
}
}
}
}
ll n,m;
ll fa[MAXN],dep[MAXN];
void dfs(ll u){
for(auto i:adj[u]){
ll v=i.v;
if(v==fa[u]){
continue;
}
fa[v]=u;
dep[v]=dep[u]+1;
dfs(v);
}
}
ll f[MAXN];
ll find(ll u){
return u==f[u]?u:f[u]=find(f[u]);
}
ll ans[MAXN];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=0;i<m;++i){
ll u,v,w;
cin>>u>>v>>w;
adj[u].push_back({i,u,v,w});
adj[v].push_back({i,v,u,w});
e.push_back({i,u,v,w});
}
dijkstra();
for(int i=1;i<=n;++i){
adj[i].clear();
f[i]=i;
ans[i]=-1;
}
memset(vis,false,sizeof(vis));
for(int i=2;i<=n;++i){
ll u=e[fe[i]].u,v=e[fe[i]].v,w=e[fe[i]].w;
adj[u].push_back({i,u,v,w});
adj[v].push_back({i,v,u,w});
vis[fe[i]]=true;
}
for(int i=0;i<m;++i){
if(!vis[i]){
E.push_back(e[i]);
}
}
dfs(1);
sort(E.begin(),E.end());
for(auto ee:E){
ll u=ee.u,v=ee.v,w=ee.w,val=dis[u]+dis[v]+w;
u=find(u);
v=find(v);
while(u!=v){
if(dep[u]<dep[v]){
swap(u,v);
}
ans[u]=val-dis[u];
f[u]=fa[u];
u=find(u);
}
}
for(int i=2;i<=n;++i){
cout<<ans[i]<<endl;
}
return 0;
}