题意
给定一个 \(N\) 个点,\(M\) 条有向边的带非负权图,请你计算从 \(S\) 出发,到每个点的距离。
数据保证你能从 \(S\) 出发到任意点。
\(1≤N≤100000\);
\(1≤M≤200000\);
分析
可以斐波那契堆。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cstring>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
rg T data=0;
rg int w=1;
rg char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
{
data=data*10+ch-'0';
ch=getchar();
}
return data*w;
}
template<class T>T read(T&x)
{
return x=read<T>();
}
typedef long long ll;
co ll INF=0x7fffffffffffffff;
co int N=1e5+7;
int root;
namespace FIB
{
using std::vector;
using std::swap;
co double PHI=(sqrt(5)+1)/2; // log_{PHI}(N)=ln(N)/ln(PHI)
// Heap node definitions
int sz;
int fa[N],ch[N];
int left[N],right[N];
int degree[N];
bool mark[N];
ll val[N];
// Heap node operations
int newnode(int nd,ll v)
{
fa[nd]=0,ch[nd]=0;
left[nd]=right[nd]=nd;
degree[nd]=0;
mark[nd]=false;
val[nd]=v;
return nd;
}
void add(int r,int x)
{
assert(r&&x);
left[right[r]]=x,right[x]=right[r];
right[r]=x,left[x]=r;
}
void del(int r)
{
left[right[r]]=left[r];
right[left[r]]=right[r];
left[r]=right[r]=r; // edit 2
}
// Heap definitions
int nm;
int min[2],siz[2];
// Heap operations
int NewHeap()
{
++nm;
min[nm]=0;
siz[nm]=0;
return 0;
}
void Insert(int H,int x)
{
if(!min[H])
min[H]=x;
else
{
add(min[H],x);
if(val[x]<val[min[H]])
min[H]=x;
}
++siz[H];
}
int Minimum(int H)
{
return min[H];
}
int Union(int H1,int H2)
{
if(!min[H1])
return H2;
if(!min[H2])
return H1;
int t=min[H2];
while(min[H2])
{
int x=min[H2];
if(x==right[x])
min[H2]=0;
else
min[H2]=right[x];
del(x);
add(min[H1],x);
}
if(val[t]<val[min[H1]])
min[H1]=t;
siz[H1]+=siz[H2];
return H1;
}
void Link(int y,int x)
{
del(y);
if(!ch[x])
ch[x]=y;
else
add(ch[x],y);
fa[y]=x;
++degree[x];
mark[y]=false;
}
void Consolidate(int H)
{
co int D=log(siz[H])/log(PHI)+1;
vector<int>A(D);
fill(A.begin(),A.end(),0);
while(min[H]) // edit 1
{
int x=min[H];
if(right[x]==x)
min[H]=0;
else
min[H]=right[x];
del(x);
int d=degree[x];
while(A[d])
{
int y=A[d];
if(val[x]>val[y])
swap(x,y);
Link(y,x);
A[d]=0;
++d;
}
assert(d<D);
A[d]=x;
}
min[H]=0;
for(int i=0;i<D;++i)
if(A[i])
{
if(!min[H])
min[H]=A[i];
else
{
add(min[H],A[i]);
if(val[A[i]]<val[min[H]])
min[H]=A[i];
}
}
}
int ExtractMin(int H)
{
int z=min[H];
if(z)
{
while(ch[z])
{
int x=ch[z];
if(right[x]==x)
ch[z]=0;
else
ch[z]=right[x];
del(x);
add(z,x);
fa[x]=0;
}
if(z==right[z])
min[H]=0;
else
{
min[H]=right[z];
del(z);
Consolidate(H);
}
--siz[H];
}
return z;
}
void Cut(int H,int x,int y)
{
if(x==right[x]) // edit 3
ch[y]=0;
else
{
ch[y]=right[x];
del(x);
}
--degree[y];
add(min[H],x);
fa[x]=0;
mark[x]=false;
}
void CascadingCut(int H,int y)
{
int z=fa[y];
if(z)
{
if(mark[y]==false)
mark[y]=true;
else
{
Cut(H,y,z);
CascadingCut(H,z);
}
}
}
void DecreaseKey(int H,int x,ll v)
{
assert(v<=val[x]);
val[x]=v;
int y=fa[x];
if(y&&val[x]<val[y])
{
Cut(H,x,y);
CascadingCut(H,y);
}
if(val[x]<val[min[H]])
min[H]=x;
}
void Delete(int H,int x)
{
DecreaseKey(H,x,-INF);
ExtractMin(H);
}
}
using namespace FIB;
using namespace std;
int n,m,s;
vector<pair<int,ll> >g[N];
ll dis[N];
bool inh[N];
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),read(m),read(s);
for(int i=1;i<=m;++i)
{
int x=read<int>(),y=read<int>();
ll w=read<ll>();
g[x].push_back(make_pair(y,w));
}
root=NewHeap();
fill(dis+1,dis+n+1,INF);
dis[s]=0;
Insert(root,newnode(s,0));
inh[s]=1;
while(siz[root])
{
int x=Minimum(root);
ExtractMin(root);
inh[x]=0;
for(int i=0;i<g[x].size();++i)
{
int y=g[x][i].first,w=g[x][i].second;
if(dis[x]+w<dis[y])
{
dis[y]=dis[x]+w;
if(!inh[y])
{
Insert(root,newnode(y,dis[y]));
inh[y]=1;
}
else
DecreaseKey(root,y,dis[y]);
}
}
}
for(int i=1;i<=n;++i)
printf("%lld ",dis[i]);
return 0;
}