BZOJ 4239 巴士走读

最短路

和正解的做法不一样,不过都是 O((q+n)logm) 的。

我的做法:也是最短路。把巴士看成点,并拆成入点和出点,边权为y-x(走它的意义是坐了这个巴士)。对于每一个原图的点u,把所有从这里出去的巴士按x排序,x小的前一辆i-1的入点向后一辆i的入点连边,边权x[i]-x[i-1](走它的意义是去考虑坐i号巴士并消耗等车时间)。把每一辆进入u的巴士的出点连向所有离开u的巴士中x恰好大于它的y的巴士的入点,边权为出去的那辆巴士的y-进入的那辆巴士的x(走它的意义是换车的等车时间)。跑最短路之后在s的出边二分即可。

正解(贴PO爷原文,戳我查看原文):将二元组<站点,时间>看做一个点,那么点数是O(m)的 ,每辆巴士连一条边,每个点向下一个时间连边,然后将所有边反向 ,枚举终点站的每一个时间,加入队列广搜,得到最晚多久到达1号站点可以在这个时间到达终点站,然后对于每个询问去数组中二分即可

好气啊,不知道怎么的刚开始偏大数据拍WA了,后来代码没改重新拍又拍不WA了,交上去居然A了。。。呵呵呵呵

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 600005
using namespace std;
namespace runzhe2000
{
    int read()
    {
        int r = 0; char c = getchar();
        for(; c < '0' || c > '9'; c = getchar());
        for(; c >='0' && c <='9'; c = getchar()) r=r*10+c-'0';
        return r;
    }
    const int INF = 1<<28;
    int n, m, last[N], ecnt, dis[N], T;
    bool vis[N];
    vector<int> in[N], out[N];
    struct edge{int next, to, val;}e[N<<1];
    struct Bus{int a, b, x, y;}bus[N]; 
    struct item{int x, dis;};
    bool operator < (item a, item b) {return a.dis > b.dis;}
    bool cmp(int i1, int i2){return bus[i1].x < bus[i2].x;}
    void addedge(int a, int b, int c){e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt;}
    int pack(int i, int j){return i*2+j;}
    void dijkstra()
    {
        memset(dis, 63, sizeof(dis));
        priority_queue<item> q;
        q.push((item){T, dis[T] = 0});
        for(; !q.empty(); )
        {
            int x = q.top().x; q.pop();
            if(vis[x])continue; vis[x] = 1;
            for(int i = last[x]; i; i = e[i].next)
            {
                int y = e[i].to;
                if(dis[x] + e[i].val <  dis[y]) 
                    q.push((item){y, dis[y] = dis[x] + e[i].val});
            }
        }
    }
    void main()
    {
        n = read(), m = read();
        for(int i = 1; i <= m; i++)
        {
            bus[i].a = read(), bus[i].b = read(), bus[i].x = read(), bus[i].y = read();
            out[bus[i].a].push_back(i);
            in[bus[i].b].push_back(i);
            addedge(pack(i, 1), pack(i, 0), bus[i].y - bus[i].x);
        }
        for(int i = 1; i <= n; i++)
            out[i].push_back(0);
        bus[0].x = INF, bus[0].y = INF+INF;
        for(int i = 1; i < n; i++)
        {
            sort(out[i].begin(), out[i].end(), cmp);
            for(int j = 0; j < (int)in[i].size(); j++)
            {
                int u = in[i][j], l = 0, r = (int)out[i].size()-1;
                for(; l < r; )
                {
                    int mid = (l+r)>>1;
                    if(bus[out[i][mid]].x >= bus[u].y) r = mid;
                    else l = mid+1;
                }
                addedge(pack(out[i][l], 0), pack(u, 1), bus[out[i][l]].x - bus[u].y);
            }
            for(int j = 1; j < (int)out[i].size(); j++) 
                addedge(pack(out[i][j], 0), pack(out[i][j-1], 0), bus[out[i][j]].x - bus[out[i][j-1]].x);
        }
        T = pack(m+1,0);
        for(int i = 0; i < (int)in[n].size(); i++)
            addedge(T, pack(in[n][i], 1), 0);
        dijkstra();
        for(int i = 0; i < (int)out[1].size(); i++)
            dis[pack(out[1][i], 0)] += bus[out[1][i]].x;
        for(int Q =read(), t; Q--; )
        {
            t = read();
            int l = 0, r = out[1].size() - 1;
            for(; l < r; )
            {
                int mid = (l+r+1)>>1;
                if(dis[pack(out[1][mid], 0)] <= t) l = mid;
                else r = mid - 1;
            }
            if(dis[pack(out[1][l], 0)] <= t) printf("%d\n",bus[out[1][l]].x);
            else puts("-1");
        }
    }
}
int main()
{
    runzhe2000::main();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值