atc abc463E 思路分享(最短路)

https://atcoder.jp/contests/abc463/tasks/abc463_e

题意

给定一张带边权无向图,另外任意两点 \(i,j\) 之间有传送门,代价为 \(X_i+X_j+Y\),求 \(1\) 到其他点的最短路.

\(2\le n \le 2\times 10^5\)\(0 \le m \le 2\times 10^5\).

思路

完全图中 \(i,j\) 的边权能拆成只与 \(i\)\(j\) 单独有关的两部分,可以引入虚拟点 \(s\),连 \(i\to s\) 权值为 \(X_i+Y\) 的边,以及 \(s\to j\) 权值为 \(X_j\) 的边,这样边的数量就压到了 \(2n\).

时间复杂度 \(\mathcal{O}((n+m)\log n)\).

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll INF = 9e18;

void solve(){
    int n,m,Y;
    cin >> n >> m >> Y;

    vector<vector<pair<ll,int>>> adj(n+1);
    for (int i=0;i<m;i++){
        int u,v,w;
        cin >> u >> v >> w;
        adj[u].emplace_back(w,v);
        adj[v].emplace_back(w,u);
    }

    vector<int> X(n+1);
    for (int i=1;i<=n;i++){
        cin >> X[i];
    }

    for (int i=1;i<=n;i++){
        adj[i].emplace_back(Y+X[i],0);
        adj[0].emplace_back(X[i],i);
    }

    vector<ll> dis(n+1,INF);
    dis[1] = 0;
    priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<>> pq;
    pq.emplace(0,1);

    while (!pq.empty()){
        auto [d,u] = pq.top();
        pq.pop();
        if (d>dis[u]) continue;

        for (auto& [w,v]:adj[u]){
            if (d+w<dis[v]){
                dis[v] = d+w;
                pq.emplace(dis[v],v);
            }
        }        
    }

    for (int i=2;i<=n;i++){
        cout << dis[i] << ' ';
    }
    cout << '\n';
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int t = 1;
    // cin >> t;
    while (t--) solve();

    return 0;
}
posted @ 2026-07-31 19:51  kzssCCC  阅读(7)  评论(0)    收藏  举报