学习成神之路

爱情和编程,你选择哪个

5597. 红绿灯

题目大意:

你从起点走到终点,中间有很多的红绿灯,遇到红灯不能走,要等到绿灯。红灯和绿灯都是固定的G,R时间。你会从T时刻出发,问到达终点的时间是什么时候。

思路:

这题和2018 GDKOI T1差不多..算法虽然不同,但是他的思路是差不多的。走到一个红灯,后面需要走的时间就是一个固定的常数了,所以只需要求出遇到第一个红灯需要的时间,以及每个点为0时刻出发到终点的时间。
我们讨论如何找第一个红灯。预处理同理。
我们发现当T%(G+R)在区间[G,G+R]的时候就会遇到红灯。所以我们只要维护一个在区间里面编号最小的值,因为G,R比较大,所以不能暴力维护,要用权值线段树离散。

程序:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define N 50005
#define inf 0x3f3f3f3f
using namespace std;
int ls[N*2],rs[N*2],val[N*2];
LL d[N],f[N],sum[N],b[N],c[N];
LL g,r;
int n,q,rt,cnt,m;
void ins(int &x,int l,int r,int pos,int w){
    if (!x) x=++cnt;
    if (l==r) {val[x]=min(val[x],w); return;}
    int mid=(l+r)>>1;
    if (pos<=mid) ins(ls[x],l,mid,pos,w);
    else ins(rs[x],mid+1,r,pos,w);
    val[x]=min(val[ls[x]],val[rs[x]]);
}

int qry(int x,int l,int r,int l1,int r1){
    if (!x||l1>r1) return inf;
    if (l>=l1&&r<=r1) return val[x];
    LL mid=(l+r)>>1; 
    int ret=inf;
    if (l1<=mid) ret=qry(ls[x],l,mid,l1,r1);
    if (r1>mid) ret=min(ret,qry(rs[x],mid+1,r,l1,r1));
    return ret;
}

int main(){
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);
    memset(val,0x3f,sizeof(val));
    scanf("%d%lld%lld",&n,&g,&r);
    for (int i=1;i<=n+1;++i) scanf("%lld",d+i);
    for (int i=1;i<=n+1;++i) sum[i]=sum[i-1]+d[i],c[i]=b[i]=sum[i]%(g+r);
    c[n+2]=0; c[n+3]=g+r;
    sort(c+1,c+n+4);
    m=unique(c+1,c+n+4)-c-1;
    for (int i=n;i>=1;--i){
        int p;
        LL lc=(b[i]+g)%(g+r),rc=(g+r-1+b[i])%(g+r);
        int l1=lower_bound(c+1,c+m+1,lc)-c;
        int r1=upper_bound(c+1,c+m+1,rc)-c-1;
        if (lc<=rc) p=qry(rt,1,m,l1,r1);
        else p=min(qry(rt,1,m,l1,m),qry(rt,1,m,1,r1));
        if (p<inf) f[i]=sum[p]-sum[i]+g+r-(sum[p]-sum[i])%(g+r)+f[p];
        else f[i]=sum[n+1]-sum[i];
        ins(rt,1,m,lower_bound(c+1,c+m+1,b[i])-c,i);
    }
    scanf("%d",&q);
    while (q--){
        LL t,y; int p;
        scanf("%lld",&t); y=(g+r-t%(g+r))%(g+r);
        LL lc=(y+g)%(g+r),rc=(g+r-1+y)%(g+r);
        int l1=lower_bound(c+1,c+m+1,lc)-c;
        int r1=upper_bound(c+1,c+m+1,rc)-c-1;
        if (lc<=rc) p=qry(rt,1,m,l1,r1);
        else p=min(qry(rt,1,m,l1,m),qry(rt,1,m,1,r1));
        if (p<inf) printf("%lld\n",sum[p]+f[p]+g+r-(sum[p]+t)%(g+r)+t);
        else printf("%lld\n",sum[n+1]+t);
    }
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq872425710/article/details/79953612
文章标签: 何嘉阳
个人分类: 线段树
想对作者说点什么? 我来说一句

plc红绿灯程序及原理图

2015年06月12日 2.45MB 下载

Unity3D红绿灯实现步骤

2014年05月18日 12KB 下载

红绿灯控制器说明及接线图

2008年09月12日 52KB 下载

基于51单片机红绿灯程序设计

2014年03月10日 23KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭