LG4779 【模板】單源最短路徑(標準版)
阿新 • • 發佈:2019-01-02
題意
給定一個 \(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; }