Codeforces 85B. Embassy Queue【段树、馋】

标题效果:

每个人都应该申请签证必须向大使馆3种程序,而这3个步骤做的顺序是固定的。通过各种形式的手续给出多少,它需要对每个过程的处理时间,有多少人会来办理手续,什么时间来。要求的是全部人分别在大使馆待的最长时间是多少。


做法:

一种贪心的做法,由于仅仅有三种手续,那么每一个人进入办理的时候, 保证选办理同种手续的全部窗体中最早等待的那一个窗体(为什么会有等待?由于该窗体办完了上一个,而下一个没能立即到这一个窗体)。接下来对每一个人分开处理,计算出每一个人从进入大使馆到办完三种手续离开大使馆须要多少时间。最后去最大的一个即可。

那么关键点就是怎么计算出这个时间。

前面已经提到。仅仅须要去每种窗体最早等待的那一个窗体就可以,那么这种话。我们须要知道 同种类型的窗体的处于等待的时间的最小值。而且改动这个最小值。

涉及到这种操作的话,那当然想到了线段树。

我们用三个线段树,分别处理不同类型的窗体的信息。

那有人会想,窗体的个数不是多达10^9个吗?怎么建立这种线段树?事实上这仅仅是个障眼法,总人数最多仅仅能由10^5个,那么最多会用到的窗体最多也就10^5个而已。我们建立树的时候仅仅须要建立窗体数和人数的较小值就可以。那这样终于复杂度为O(n*logn)。

代码:
#include <iostream>
#include <cstdio>
#include <climits>
#include <algorithm>
#define N 100010
#define L(x) (x)<<1
#define R(x) (x)<<1|1
using namespace std;
struct node
{
    long long ll,rr,mi,pos;
    node()
    {
        ll=rr=pos=0;
        mi=INT_MAX;
    }
    node(long long l,long long r,long long m,long long p)
    {
        ll=l,rr=r,mi=m,pos=p;
    }
}ty[4][N*4];
long long k[4][N],n[4],t[4],peo[N];
long long nn;
void bulid(long long id,long long l,long long r,long long na)
{
    ty[na][id]=node(l,r,0,l);
    if(l==r) return ;
    long long mid=(l+r)/2;
    bulid(L(id),l,mid,na);
    bulid(R(id),mid+1,r,na);
}
void update(long long id,long long k,long long a,long long na)
{
    if(k==ty[na][id].ll && ty[na][id].rr==k){ty[na][id].mi=a;return ;}
    long long mid=(ty[na][id].ll+ty[na][id].rr)/2;
    if(k>mid) update(R(id),k,a,na);
    else update(L(id),k,a,na);
    if(ty[na][L(id)].mi<=ty[na][R(id)].mi)
    {
        ty[na][id].mi=ty[na][L(id)].mi;
        ty[na][id].pos=ty[na][L(id)].pos;
    }
    else
    {
        ty[na][id].mi=ty[na][R(id)].mi;
        ty[na][id].pos=ty[na][R(id)].pos;
    }
}
long long query(long long id,long long l,long long r,long long na,long long &index)
{
    if(ty[na][id].ll==l&&ty[na][id].rr==r)
    {
        index=ty[na][id].pos;
        return ty[na][id].mi;
    }
    long long mid=(ty[na][id].ll+ty[na][id].rr)/2;
    if(mid>=r) return query(L(id),l,r,na,index);
    else if(mid<l) return query(R(id),l,r,na,index);
    else
    {
        long long tmp1,tmp2;
        long long t1=query(L(id),l,mid,na,tmp1);
        long long t2=query(R(id),mid+1,r,na,tmp2);
        if(t1<=t2) {index=tmp1;return t1;}
        else {index=tmp2;return t2;}
    }
}
int main()
{
    for(long long i=1;i<=3;i++)
        scanf("%I64d",&n[i]);
    for(long long i=1;i<=3;i++)
        scanf("%I64d",&t[i]);
    scanf("%d",&n[0]);
    for(long long i=0;i<n[0];i++)
        scanf("%I64d",peo+i),peo[i]--;

    for(long long i=1;i<=3;i++)
        bulid(1,1,min(n[i],n[0]),i);
    long long ans=0;
    for(long long i=0;i<n[0];i++)
    {
        long long cur=peo[i];
        for(long long j=1;j<=3;j++)
        {
            long long index;
            long long c_mi=query(1,1,min(n[j],n[0]),j,index);
            if(c_mi>=cur) cur=c_mi+t[j];
            else cur+=t[j];
            update(1,index,cur,j);
        }
        ans=max(ans,cur-peo[i]);
    }
    cout<<ans<<endl;
    return 0;
}


版权声明:本文博主原创文章。博客,未经同意不得转载。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值