Description
太空中一共有n座星球,它们之间可以通过空间传送装置进行转移。空间传送装置分为m种,第i种装置可以用4个参
数a_i,b_i,c_i,d_i来描述。因为时空抖动的问题,在非整数时刻禁止使用空间传送装置。如果在整数s时刻使用装
置,那么需要花费((a_i*s+b_i) mod c_i)+d_i单位时间才能完成传送。现在是s时刻,小Q位于1号星球,请写一个
程序计算从1号星球到每个星球最少需要的时间。
Input
第一行包含4个正整数n,m,s,e(2<=n<=100000,1<=m<=50,1<=s<=2000,1<=e<=200000)
分别表示星球的个数、空间传送装置的种类数、当前的时间以及空间传送装置的个数。
接下来m行,每行4个正整数a_i,b_i,c_i,d_i(1<=a_i,b_i,c_i,d_i<=2000),依次描述每种装置的参数。
接下来e行,每行3个正整数u_i,v_i,w_i(1<=u_i,v_i<=n,u_i!=v_i,1<=w_i<=m)
表示从星球u_i可以使用第w_i种装置单向传送到星球v_i。
Output
输出n-1行,每行一个整数,第i行表示从1到i+1的最少所需时间,若无解输出-1。
Sample Input
3 2 1 3
1 1 5 1
2 2 7 1
1 2 1
2 3 2
3 1 1
1 1 5 1
2 2 7 1
1 2 1
2 3 2
3 1 1
Sample Output
3
6
HINT
1到3:在时刻1使用第一种装置从1传送到2,花费时间3,再等待2单位时间,于时刻6使用第二种装置到达3,花费时间1。
6
HINT
1到3:在时刻1使用第一种装置从1传送到2,花费时间3,再等待2单位时间,于时刻6使用第二种装置到达3,花费时间1。
虽然每个时刻的传送时间不同,但是越早到,就越早能传送出去(即使需要等待一段时间再传送)。这样就转化成一个最短路问题。
需要先预处理f[i][j],用第i个传送装置在第j时刻传送所需要的最少时间。因为下一次传送计算时刻时需要%ci。所以j的范围在[0,c[i]-1]。用前缀和后缀的最小值维护f[i][j]。
//
// main.cpp
// bzoj5047
//
// Created by zc on 2017/10/17.
// Copyright © 2017年 zc. All rights reserved.
//
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int M=55;
const int S=2200;
int n,m,ss,ee;
int a[M],b[M],c[M],f[M][S*2];
template <class T>
bool read(T &ret)
{
char c;
int sgn;
T bit = 0.1;
if (c=getchar(), c==EOF)
{
return 0;
}
while (c != '-' && c != '.' && (c < '0' || c > '9'))
{
c = getchar();
}
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9')
{
ret = ret * 10 + (c - '0');
}
if (c == ' ' || c == '\n')
{
ret *= sgn;
return 1;
}
while (c = getchar(), c >= '0' && c <= '9')
{
ret += (c - '0') * bit, bit /= 10;
}
ret *= sgn;
return 1;
}
const int maxn=100000+5;
struct Edge{
int from,to,weight;
Edge(int from,int to,int weight):from(from),to(to),weight(weight){}
};
struct HeapNode{ //prority_queue 中的优先级
int u,dist; //dist: u点到起点的最短路 ,u: 有向边的终点
HeapNode(int u,int d):u(u),dist(d){}
bool operator < (const HeapNode& h) const {
return dist>h.dist;
}
};
struct Dijkstra{ //打包在Dijkstra中
int n,m;
vector<Edge> edges;
vector<int> G[maxn];
bool done[maxn];
int dist[maxn];
int p[maxn];
Dijkstra(int n):n(n){
for(int i=0;i<n;i++) G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int weight){
edges.push_back(Edge(from,to,weight));
m=edges.size();
G[from].push_back(m-1); //保存from出发的边
}
void dijkstra(int s)
{
priority_queue<HeapNode> Q;
memset(dist,0x3f,sizeof(dist));
memset(done,false,sizeof(false));
dist[s]=ss;
Q.push(HeapNode(s,0));
while(!Q.empty())
{
int u=Q.top().u; Q.pop();
if(done[u]) continue;
done[u]=true;
for(int i=0;i<G[u].size();i++)
{
Edge& e=edges[G[u][i]];
int v=e.to ,w=e.weight;
if(dist[v]>dist[u]+f[w][dist[u]%c[w]])
{
dist[v]=dist[u]+f[w][dist[u]%c[w]];
p[v]=G[u][i]; //记录到各点的最短路径
Q.push(HeapNode(v,dist[v]));
}
}
}
}
};
int d[M],tmp1[S],tmp2[S],val[S];
int main(int argc, const char * argv[]) {
read(n);read(m);read(ss);read(ee);
for(int i=1;i<=m;i++)
{
read(a[i]);read(b[i]);read(c[i]);read(d[i]);
for(int j=0;j<c[i];j++) val[j]=(a[i]*j+b[i])%c[i]+d[i];
tmp1[0]=val[0],tmp2[c[i]-1]=c[i]-1+val[c[i]-1];
for(int j=1;j<c[i];j++) tmp1[j]=min(tmp1[j-1],j+val[j]);
for(int j=c[i]-2;j>=0;j--) tmp2[j]=min(tmp2[j+1],j+val[j]);
for(int j=0;j<c[i];j++) f[i][j]=min(c[i]-j+tmp1[j],tmp2[j]-j);
}
Dijkstra d(n);
for(int i=0;i<ee;i++)
{
int u, v, w;
read(u);read(v);read(w);
d.AddEdge(u, v, w);
}
d.dijkstra(1);
for(int i=2;i<=n;i++)
if(d.dist[i]>=INF)
printf("-1\n");
else
printf("%d\n",d.dist[i]-ss);
}