洛谷 2384 最短路

【题解】

  直接把松弛操作中dis[to]=dis[now]+e[i].dis改成dis[to]=dis[now]*e[i].dis是不行的,因为这样做会爆long long. 同时也可以发现在最短路中我们并不能边松弛边取模,这会导致答案错误。

  其实我们可以把边权取个log. 因为log(M*N)=logN+logM, 所以转化成了加法的操作,这就变成了传统的最短路。我们在最短路中顺便记录路径,然后再顺着路径走一遍求出边权之积即可。

  

 1 // luogu-judger-enable-o2
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #define N 1010
 6 #define M 1000010
 7 #define rg register
 8 #define inf (1e9)
 9 #define LL long long
10 #define Mod (9987)
11 using namespace std;
12 int n,m,s,tot,last[N],pos[N],from[N],way[N];
13 LL ans=0;
14 double dis[N];
15 struct edge{
16     int to,pre,dis;
17 }e[M];
18 struct heap{
19     int poi;
20     double dis;
21 }h[N];
22 inline int read(){
23     int k=0,f=1; char c=getchar();
24     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
25     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
26     return k*f;
27 } 
28 inline void add(int x,int y,int z){
29     e[++tot]=(edge){y,last[x],z}; last[x]=tot;
30 }
31 inline void up(int x){
32     int fa;
33     while((fa=x>>1)&&h[fa].dis>h[x].dis){
34         swap(h[x],h[fa]); swap(pos[h[x].poi],pos[h[fa].poi]);
35         x=fa;
36     }
37 }
38 inline void down(int x){
39     int son;
40     while((son=x<<1)<=tot){
41         if(son<tot&&h[son].dis>h[son+1].dis) son++;
42         if(h[son].dis<h[x].dis){
43             swap(h[x],h[son]); swap(pos[h[x].poi],pos[h[son].poi]);
44             x=son;
45         }
46         else return;
47     }
48 }
49 inline void dijkstra(int x){
50     h[tot=pos[x]=1]=(heap){x,dis[x]=0};
51     while(tot){
52         int now=h[1].poi; h[1]=h[tot--]; if(tot) down(1);
53         for(rg int i=last[now],to;i;i=e[i].pre)
54         if(dis[to=e[i].to]>dis[now]+log(e[i].dis)){
55             dis[to]=dis[now]+log(e[i].dis);
56             from[to]=now; way[to]=i;
57             if(!pos[to]) h[pos[to]=++tot]=(heap){to,dis[to]};
58             else h[pos[to]].dis=dis[to];
59             up(pos[to]);
60         }
61     }
62 }
63 int main(){
64     n=read(); m=read();
65     for(rg int i=1;i<=n;i++) dis[i]=inf;
66     while(m--){
67         int u=read(),v=read();
68         add(u,v,read());
69     }
70     dijkstra(1);
71     int tmp=n;
72     ans=e[way[tmp]].dis%Mod;
73     while(tmp=from[tmp]){
74         if(tmp==1) break;
75         ans*=e[way[tmp]].dis;
76         ans%=Mod;
77     }
78     printf("%lld
",ans);
79     return 0;
80 }
View Code
原文地址:https://www.cnblogs.com/DriverLao/p/8688015.html