题意
在遥远的未来,行星之间的食品运输将依靠单向的贸易路线。每条路径直接连接两个行星,且其运输时间是已知的。贸易商协会打算利用一项最近发现的新技术——超空间旅行,以增加一些新的航线。通过超空间旅行的航线也是单向的。由于该项技术仍处于试验阶段,超空间旅行的时间目前是未知的,但它不取决于行星之间的距离,所以每个超空间旅行的路线将花费等量的时间。下图是三个相互联通的行星及其运输时间的例子。行星使用正整数标号,超空间旅行时间记为“x”(图片对应第输入样例):过境的时间以天计,并且始终是一个正整数。贸易商协会希望对引进新航线的后果进行分析:对于某两个行星A和B,他们想知道对于任意的x,从A到B的最短路径的总中转时间的所有可能的值。
输入的第一行包含两个整数P和R,分别代表行星的数目和航线数量,1≤P≤500,0≤R≤10000。接下来的R条航线路径包含两或三个整数:行星标号C和D(1≤C,D≤P,C≠D),和T,从C到D的旅行时间。对于传统的路径,T是一个整数(1≤T≤1000000),超空间航线中,T是字符“x”。 可以存在多行有两个相同的行星。下面的行中包含的整数Q(1≤Q≤10),表示查询的数量。以下Q行包含两个整数星球标号(A和B,A≠B),为贸易商协会的查询:“从A到B的最短路径时间的可能值是什么?
输出必须包含Q行。
每一行都必须包含两个整数:不同的可能值的数目和它们的总和。如果不同的可能值的数目是无限的,该行只输出“inf”。如果不存在从A到B的路径,不同的可能值的数目及它们的总和都是0。
分析
首先跑分层图最短路,设f[i,j]表示走到点i走了j次x边的最短路。
然后对这若干条直线维护一个上凸壳,每一段用等差数列分别算贡献即可。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N=505;
int n,m,q,cnt,last[N],stack[N],dis[N][N],s,t;
bool vis[N][10005];
struct edge{int to,next,w;}e[10005];
priority_queue<pair<int,pair<int,int> > > que;
double b[N];
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='x'){if(ch=='-')f=-1;ch=getchar();}
if (ch=='x') return 0;
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void addedge(int u,int v,int w)
{
e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;
}
void dij()
{
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s][0]=0;que.push(make_pair(0,make_pair(s,0)));
while (!que.empty())
{
pair<int,pair<int,int> > u=que.top();que.pop();
while (!que.empty()&&vis[u.second.first][u.second.second]) u=que.top(),que.pop();
if (vis[u.second.first][u.second.second]) break;
int x=u.second.first,y=u.second.second;
vis[x][y]=1;
for (int i=last[x];i;i=e[i].next)
if (!e[i].w)
{
if (y==n) continue;
if (dis[x][y]<dis[e[i].to][y+1])
{
dis[e[i].to][y+1]=dis[x][y];
que.push(make_pair(-dis[e[i].to][y+1],make_pair(e[i].to,y+1)));
}
}
else
{
if (dis[x][y]+e[i].w<dis[e[i].to][y])
{
dis[e[i].to][y]=dis[x][y]+e[i].w;
que.push(make_pair(-dis[e[i].to][y],make_pair(e[i].to,y)));
}
}
}
}
double get(int x,int y)
{
return (double)(dis[t][y]-dis[t][x])/(x-y);
}
LL calc(int k,int b,int l,int r)
{
return (LL)((LL)k*(l+r)+(LL)b*2)*(r-l+1)/2;
}
void solve()
{
dij();
int flag=0;
for (int i=0;i<=n;i++) if (dis[t][i]!=inf) {flag=1;break;}
if (!flag) {puts("0 0");return;}
if (dis[t][0]==inf) {puts("inf");return;}
int top=0;
for (int i=n;i>=0;i--)
{
if (dis[t][i]==inf) continue;
while (top&&b[top]>=get(stack[top],i)) top--;
if (top) b[top+1]=get(stack[top],i);
stack[++top]=i;
}
LL ans=0;
for (int i=1;i<top;i++) ans+=calc(stack[i],dis[t][stack[i]],(int)b[i]+1,(int)b[i+1]);
int num=b[top];
if (num*stack[top-1]+dis[t][stack[top-1]]!=dis[t][0]||top==1) ans+=dis[t][0],num++;
printf("%d %lld\n",num,ans);
}
int main()
{
n=read();m=read();
for (int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read();
addedge(x,y,z);
}
q=read();
while (q--)
{
s=read();t=read();
solve();
}
return 0;
}