好神啊。。。
考虑维护d[i][j]表示st到i需要经过j个为x的边的最短路,这个就是分层图的最短路了
然后就可以发现,y=kx+b其中k=j,b=d[i][j],有很多直线,然后我们要的就是一个单增的上凸包
这个直线最多只有n条,因为一个点经过多次肯定就是有环,那么一定不优
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> using namespace std; typedef long long LL; const int _=1e2; const int maxn=5*1e2+_; const int maxm=1e4+_; const double eps=1e-8; struct node { int x,y,next;LL d; }a[maxm];int len,last[maxn]; void ins(int x,int y,LL d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } //----------------------------------------------def--------------------------------------------------------- int n,st,ed; struct dij { int x,c;LL d; dij(){} dij(int X,int C,LL D){x=X,c=C,d=D;} friend bool operator >(dij d1,dij d2){return d1.d>d2.d;} friend bool operator <(dij d1,dij d2){return d1.d<d2.d;} };priority_queue< dij,vector<dij>,greater<dij> >q; int mc; LL d[maxn][maxn]; bool v[maxn][maxn];//不可能跑环(不优),所以只需要点数步 void dijkstra() { memset(d,63,sizeof(d));d[st][0]=0; memset(v,false,sizeof(v)); q.push(dij(st,0,d[st][0])); while(!q.empty()) { dij tno=q.top();q.pop(); int x=tno.x,c=tno.c; if(x==ed)mc=max(mc,c); if(v[x][c]==true)continue; v[x][c]=true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].d<0) { if(d[y][c+1]>d[x][c]&&c<n) { if(y==ed) { int q;q++; } d[y][c+1]=d[x][c]; q.push(dij(y,c+1,d[y][c+1])); } } else { if(d[y][c]>d[x][c]+a[k].d) { d[y][c]=d[x][c]+a[k].d; q.push(dij(y,c,d[y][c])); } } } } } //----------------------------------------------dij--------------------------------------------------------- //系数k: 0~n: d值 double getx(int i,int j){return double(d[ed][j]-d[ed][i])/double(i-j);} LL gg(int i,int j)//i管理的范围的后界 { double x=getx(i,j); if(fabs(double(x)-double(int(x)))<=eps)x-=0.5; return int(floor(x)); } int top,sta[maxm]; char ss[10]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int m,x,y,dd; scanf("%d%d",&n,&m); len=1; for(int i=1;i<=m;i++) { scanf("%d%d%s",&x,&y,ss+1); if(ss[1]=='x')ins(x,y,-1); else { int sslen=strlen(ss+1); dd=0;for(int i=1;i<=sslen;i++)dd=dd*10+ss[i]-'0'; ins(x,y,dd); } } int Q; scanf("%d",&Q); while(Q--) { scanf("%d%d",&st,&ed); mc=-1;dijkstra(); if(mc==-1)puts("0 0"); else if(d[ed][0]==d[0][0])puts("inf"); else { top=1;sta[top]=0; for(int i=1;i<=mc;i++) if(d[ed][i]!=d[0][0]&&d[ed][i]+i<=d[ed][sta[top]]+sta[top]) { while(top>1&& getx(i,sta[top-1])>=getx(sta[top],sta[top-1]) )top--; if(gg(i,sta[top])>0)sta[++top]=i; } LL l=1,r,ans=0; for(int i=top;i>=2;i--) { r=gg(sta[i],sta[i-1]); LL k=sta[i],b=d[ed][sta[i]]; ans+=(r-l+1)*b+((l+r)*(r-l+1)/2)*k; l=r+1; } ans+=d[ed][0]; printf("%lld %lld ",l,ans); } } return 0; }