#dijkstra,二叉堆#洛谷 5060 旅行

本文介绍了一种使用 Dijkstra 算法结合堆优化的方法来寻找最短路径的问题,特别适用于答案需要为特定数值倍数的情况。通过手写堆优化减少 STL 的依赖,并解决了在一个特殊点上 TLE 的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

找出一条最短路径,使答案为PPP的倍数


分析

那么要用dis[x][w]dis[x][w]dis[x][w]表示走到第xxx个点时最短路径 mod ppp为w的最短路径,那么其实只需要一个dijkstra+堆优化即可,但是毒瘤出题人卡STL,于是手写堆,但是我太菜了,总是T掉一个点,所以只能开O2了。


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
typedef long long ll;
struct node{int y; ll w; int next;}e[200011];
pair<ll,int>heap[2500001]; ll dis[50001][51]; bool v[51][50001];
int cnt,pre[50001][51],pis[50001][51],k=1,ls[50001],n,m,p,s,t;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void Push(pair<ll,int>d){
    heap[++cnt]=d;
    rr int x=cnt;
    while (x>1){
        if (heap[x>>1]>heap[x])
            swap(heap[x>>1],heap[x]),x>>=1;
        else return;
    }
}
inline void Pop(){
    heap[1]=heap[cnt--];
    rr int x=1;
    while ((x<<1)<=cnt){
        rr int y=x<<1;
        if (y<cnt&&heap[y+1]<heap[y]) ++y;
        if (heap[y]<heap[x]) swap(heap[y],heap[x]),x=y;
        else return;
    }
}
inline void print(int x,int y){
    if (!pre[x][y]) return;
    print(pre[x][y],pis[x][y]);
    printf("%d->",pre[x][y]);
}
signed main(){
    n=iut(); m=iut(); p=iut(); s=iut(); t=iut();
    for (rr int i=1;i<=m;++i){
        rr int x=iut(),y=iut(),w=iut();
        e[++k]=(node){y,w,ls[x]}; ls[x]=k;
    }
    memset(dis,127,sizeof(dis));
    dis[s][0]=0; heap[++cnt]=make_pair(0ll,s);
    while (cnt){
        rr ll now1=heap[1].first; rr int x=heap[1].second; Pop();
        if (now1%p==0&&x==t) break;
        v[now1%p][x]=1;
        for (rr int i=ls[x];i;i=e[i].next){
            rr ll now=dis[x][now1%p]+e[i].w;
            if (now<dis[e[i].y][now%p]){
                pre[e[i].y][now%p]=x;
                pis[e[i].y][now%p]=now1%p;
                dis[e[i].y][now%p]=now;
                if (!v[now%p][e[i].y])
                    Push(make_pair(now,e[i].y));
            }
        }
    }
    if (dis[t][0]==dis[0][0]) return !printf("jjc fails in travelling");
    printf("%lld\n",dis[t][0]);
    print(t,0); return !printf("%d",t);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值