P3103 [USACO14FEB] Airplane Boarding G

P3103 [USACO14FEB] Airplane Boarding G

想象一下飞机有N个座位,N个座位相当于数轴上的1至N共N个整点,第1个座位在整点1处,第2个座位在整点2处,……第N个座位在整点N处。

有N个奶牛排好队,要登陆坐飞机,第N头奶牛在数轴的整点0处,第N−1头奶牛在数轴的整点−1处,……第1头奶牛在数轴的整点−N+1处。第i头奶牛的座位号是Si。注意:每头奶牛都有唯一的一个座位,不会出现多头奶牛有相同的座位号。

在每一秒钟,奶牛会向右移动一步到达下一个整点,前提是没有奶牛挡住它。 当第i头奶牛到达它的座位Si时,它需要花费Ti秒去把行李放到头顶的行李架上,然后坐到自己的位置上,在此过程中,由于飞机通道很窄,所以在第i头奶牛坐到自己座位之前,在它左边的所有奶牛都不能动,要等奶牛i放好行李坐好后才能动。

现在的问题是,至少要多少秒之后,所有的奶牛都能做到自己的座位上?

\(N \le2*10^5\)

Solution:

妙妙平衡树思维题,感觉可以入选我写过的的十佳题目了。

我们将点 \(i\) 的起点定义为 \(pos_i\)

首先我们很难不想到我们应该按照时间的顺序,也就是输入顺序的倒序来写这题,然后我们仔细思考一下就会发现其实答案由两部分组成:

从起点到终点的距离加上放行李的时间\(s_{i}-pos_{i}+t_{i}\) 和被挡路的时间 \(tim\).

前一半的答案是固定的,所以我们要做的是如何快速的统计一个点总共会被挡多久的路。

那么什么样的点 \(j\) 会挡当前点 \(i\) 的路呢?

首先要满足的肯定是 $pos_i<pos_j $ \(s_i<s_j\)

然后就是 \(\forall k\in[i+1,j] tim_j>tim_k\)

也就是说,如果一个点 \(j\) 出发的比当前点 \(i\) 早且,而且它被挡路的时间 \(tim_j>tim_{max}\) 它才有可能挡住点 \(j\) 及其后序节点(按时间顺序)的路。所以我们要将那些不满足 \(tim_j>tim_i\) 的点全部删除。这样我们就能保证在数据结构内的点全部都是满足有可能挡住 \(i\) 的。然后每个点的到达时间显然就是该数据结构内的最大值\(tim_{max}\) 加上前半部分的时间 \(s_i+pos_i+t_i\).

然后我们发现我们要维护一种数据结构,单点插入,区间删除,查询区间最大值.那就是平衡树了

然后这题就做完了

Code:

#include<bits/stdc++.h>
const int N=2e5+5;
using namespace std;
int rd(){return rand()*17+rand()*rand()+1;}
inline int Max(int x,int y){return x>y ? x : y;}
struct FHQ_Treap{
    int cnt=0;
    struct Tree{
        int ls,rs,x,y,ans,tag,pri;
    }t[N<<2];
    int Node(int x,int y)
    {
        t[++cnt]={0,0,x,y,y,0,rd()};
        return cnt;
    }
    void push(int x,int k){t[x].x-=k;t[x].y+=k,t[x].ans+=k,t[x].tag+=k;}
    void pushdown(int x)
    {
        if(!t[x].tag)return;
        if(t[x].ls)push(t[x].ls,t[x].tag);
        if(t[x].rs)push(t[x].rs,t[x].tag);
        t[x].tag=0;
    }
    void pushup(int x)
    {
        if(!x)return;
        t[x].ans=t[x].y;
        if(t[x].ls)t[x].ans=Max(t[x].ans,t[t[x].ls].ans);
        if(t[x].rs)t[x].ans=Max(t[x].ans,t[t[x].rs].ans);
        return ;
    }
    void splite_pos(int x,int &a,int &b,int k)
    {
        if(!x){a=b=0;return;}
        pushdown(x);
        if(k>=t[x].x) {a=x;splite_pos(t[x].rs,t[x].rs,b,k);}
        if(k<t[x].x){b=x;splite_pos(t[x].ls,a,t[x].ls,k);}
        pushup(x);
    }
    void splite_val(int x,int &a,int &b,int k)
    {
        if(!x){a=b=0;return;}
        pushdown(x);
        if(k>=t[x].y) {a=x;splite_val(t[x].rs,t[x].rs,b,k);}
        if(k<t[x].y){b=x;splite_val(t[x].ls,a,t[x].ls,k);}
        pushup(x);
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x|y;
        pushdown(x);pushdown(y);
        if(t[x].pri<t[y].pri)
        {
            t[x].rs=merge(t[x].rs,y);
            pushup(x);return x;
        }
        else
        {
            t[y].ls=merge(x,t[y].ls);
            pushup(y);return y;
        }
    }
}T;
int s[N],t[N];
int n,rt,ans=0;
void work()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    rt=T.Node(0,0);
    for(int i=1;i<=n;i++)
    {
        cin>>s[i]>>t[i];
    }
    int a,b,c,tmp;
    for(int i=n;i;i--)
    {
        T.splite_pos(rt,a,b,s[i]);
        tmp=T.t[a].ans+s[i]+t[i];
        ans=Max(ans,tmp);
        T.push(a,1);
        T.splite_val(b,b,c,tmp-s[i]+1);
        rt=T.merge(a,T.merge(T.Node(s[i],tmp-s[i]+1),c));
    }
    cout<<ans;
}
int main()
{
    //freopen("P3103.in","r",stdin);freopen("P3103.out","w",stdout);
    work();
    return 0;
}
posted @ 2025-01-07 18:52  liuboom  阅读(34)  评论(0)    收藏  举报