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;
}
posted @ 2024-05-07 17:22  tanghg  阅读(10)  评论(0编辑  收藏  举报