1 条题解

  • 0
    @ 2026-6-17 1:53:02

    // 最短路径树+并查集 Dijkstra 算法 O(MlogN)
    #include<bits/stdc++.h>
    #define ll long long
    #define pli pair<ll,int>
    using namespace std;
    
    const int N=100005;
    vector<pli> e[N];
    int n,m;
    int pa[N],dep[N];
    ll d[N];
    
    void dijkstra(){
      memset(d,0x3f,sizeof d); d[1]=0;
      priority_queue<pli,vector<pli>,greater<pli> > q;
      q.push({0,1});
      while(!q.empty()){
        auto [dd,u]=q.top(); q.pop();
        if(dd!=d[u])continue;
        for(auto [w,v]:e[u]){
          if(d[v]>d[u]+w){
            d[v]=d[u]+w;
            pa[v]=u;         //记录父节点
            dep[v]=dep[u]+1; //记录深度
            q.push({d[v],v});
          }
        }
      }
    }
    
    struct node{int u,v; ll d;}nt[N<<1];
    int cnt,fa[N];
    ll ans[N];
    
    int find(int u){
      return (u==fa[u])?u:(fa[u]=find(fa[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({t,b});
        e[b].push_back({t,a});
      }
      
      dijkstra();
      for(int u=1;u<=n;u++){
        ans[u]=-1; fa[u]=u; //并查集初值
        for(auto [w,v]:e[u])if(pa[v]!=u&&pa[u]!=v&&u<v)
          nt[++cnt]={u,v,d[u]+d[v]+w}; //记录非树边
      }
      sort(nt+1,nt+cnt+1,[](node a,node b){return a.d<b.d;});
      for(int i=1;i<=cnt;i++){ //枚举非树边
        int u=nt[i].u, v=nt[i].v; ll dd=nt[i].d; //取出端点和距离
        u=find(u),v=find(v); //找出端点的根
        while(u!=v){ //都爬到lca结束
          if(dep[u]<dep[v])swap(u,v); //保证u点深
          ans[u]=dd-d[u]; //更新u点答案
          fa[u]=pa[u]; //u指向它的父亲
          u=find(u);   //找出u点的根
        }
      }
      for(int i=2;i<=n;i++)printf("%lld\n",ans[i]);
    }
    
    • 1

    D98 最短路径树+并查集 Dijkstra 算法[USACO09JAN] Safe Travel G

    信息

    ID
    836
    时间
    1000ms
    内存
    128MiB
    难度
    4
    标签
    递交数
    23
    已通过
    15
    上传者