bzoj 5047 空间传送装置 最短路

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

Sample Output

3
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);
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值