[最短路][凸壳] Jzoj P3238 超空间旅行
题解
- 首先跑分层图最短路
- 设f[i,j]表示走到点i走了j次x边的最短路
- 然后对这若干条直线维护一个上凸壳,每一段用等差数列分别算贡献即可
代码
1 #include <cmath> 2 #include <queue> 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #define ll long long 7 using namespace std; 8 const int N=510,M=1e4+10; 9 int n,m,S,T,cnt,top,s[N],head[N],bz[N][N],dis[N][N]; 10 ll sum; 11 struct EDGE{ int to,from,w; }e[M]; 12 struct node{ int x,y; }; 13 queue<node>Q; 14 void insert(int x,int y,int v) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].w=v; } 15 double calc(int x,int y) { return (dis[T][x]-dis[T][y])*1.0/(y-x); } 16 int read() 17 { 18 int x=0,f=1;char ch=getchar(); 19 while ((ch<'0'||ch>'9')&&ch!='x'){if(ch=='-')f=-1;ch=getchar();} 20 if (ch=='x') return 0; 21 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 22 return x*f; 23 } 24 int main() 25 { 26 n=read(),m=read(); 27 for (int i=1,x,y,z;i<=m;i++) x=read(),y=read(),z=read(),insert(x,y,z); 28 for (m=read();m;m--) 29 { 30 S=read(),T=read(); int flag=0,num=1; 31 while (Q.size()) Q.pop(); 32 memset(bz,1,sizeof(bz)),memset(dis,0x3f,sizeof(dis)), 33 Q.push((node){S,0}),dis[S][0]=bz[S][0]=0; 34 for (int x,y;Q.size();bz[x][y]=1) 35 { 36 x=Q.front().x,y=Q.front().y,Q.pop(); 37 if (y >= n) continue; 38 for (int i=head[x],p;i;i=e[i].from) 39 if (dis[x][y]+e[i].w<dis[e[i].to][p=y+(e[i].w==0)]) 40 dis[e[i].to][p]=dis[x][y]+e[i].w,bz[e[i].to][p]&&(Q.push((node){e[i].to,p}),bz[e[i].to][p]=0); 41 } 42 for (int i=0;i<=n;i++) flag|=dis[T][i]<0x3f3f3f3f; 43 if (!flag) { printf("0 0\n"); continue; } 44 if (dis[T][0]==0x3f3f3f3f) { printf("inf\n"); continue; } 45 s[top=1]=0; 46 for (int i=1;i<=n;i++) 47 if (dis[T][i]<dis[T][s[top]]) 48 { 49 while (top>1&&calc(s[top],s[top-1])<calc(i,s[top])) top--; 50 s[++top]=i; 51 } 52 sum=dis[T][0]; 53 for (int i=top,last=0,x;i>1;i--) x=floor((dis[T][s[i-1]]-1-dis[T][s[i]])*1.0/(s[i]-s[i-1])),sum+=(2ll*dis[T][s[i]]+1ll*s[i]*(x+last+1))*(x-last)/2ll,num=x+1,last=x; 54 printf("%d %lld\n",num,sum); 55 } 56 }