【dij变形】牛客练习赛93 C

文章讲述了如何解决一个涉及C-点权的问题,使用了Dijkstra算法进行最短路径求解。代码中定义了图结构,使用了优先队列和multiset数据结构来优化松弛操作,确保在满足特定条件下开始松弛。算法首先初始化图,然后通过Dijkstra算法遍历节点,更新最短路径,并利用multiset存储每个节点的权值信息。
摘要由CSDN通过智能技术生成

C-点权_牛客练习赛93 (nowcoder.com)

题意:

 

思路:

重要的是在松弛的时候要满足什么条件才开始松弛

这里是用两个点来松弛一个点 

 

Code:

#include <bits/stdc++.h>
 
//#define int long long
 
using namespace std;
 
const int mxn=1e5+10;
const int mxv=1e5+10;
const int mxe=1e5+10;
const int mod=1e9+7;
const int Inf=0x3f3f3f3f;

struct ty{
    int to,next,w;
}edge[mxe<<2];

struct ty2{
    int x,dis;
    bool operator<(const ty2&oth)const{
        return oth.dis<dis;
    }
};

multiset<int> S[mxn];

priority_queue<ty2> Q;

int N,u,v,w;
int tot=0;
int head[mxn],in[mxn];
int vis[mxn],dis[mxn];

void add(int u,int v,int w){
    edge[tot].w=w;
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void G_init(){
    tot=0;
    for(int i=0;i<=N;i++) head[i]=-1;
}
int get(int u){
    return (*S[u].begin())+(*(++S[u].begin()));
}
void dij(){
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=N;i++){
        if(in[i]<=1){
            Q.push({i,0});
            dis[i]=0;
        }
        S[i].insert(Inf);
        S[i].insert(Inf);
    }
    while(!Q.empty()){
        auto u=Q.top();
        Q.pop();
        if(vis[u.x]) continue;
        vis[u.x]=1;
        for(int i=head[u.x];~i;i=edge[i].next){
            S[edge[i].to].insert(dis[u.x]+edge[i].w);
            if(dis[edge[i].to]>get(edge[i].to)){
                dis[edge[i].to]=get(edge[i].to);
                if(!vis[edge[i].to]) Q.push({edge[i].to,dis[edge[i].to]});
            }
        }
    }
}
void solve(){
    cin>>N;
    G_init();
    for(int i=1;i<=N-1;i++){
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
        in[u]++;
        in[v]++;
    }
    dij();
    for(int i=1;i<=N;i++){
        if(dis[i]==Inf) cout<<-1<<" \n"[i==N];
        else cout<<dis[i]<<" \n"[i==N];
    }
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int __=1;//cin>>__;
    while(__--)solve();return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值