LG P4373 [USACO18OPEN]Train Tracking P

Description

每天早晨特快列车会经过农场,开往大城市,每天下午它又会折回来,回到郊区。今天,Bessie 会花时间观察它,早晨和下午都会。

Bessie 提前知道,列车有 $N$ 节车厢,方便起见,将其编号为 $0\sim N-1$。车厢 $i$ 有一个 ID $c_i$。在早晨和下午,所有的数字都是可见的,所以对于每节车厢 Bessie 有两次机会观察它的 ID。也就是说,当列车早晨经过的时候,Bessie 能够观察 $c_0$,然后是 $c_1$,直到 $c_{N-1}$。当列车下午驶回的时候,她又一次能够观察 $c_0$,然后是 $c_1$,直到 $c_{N-1}$。

Bessie 挑选了一个整数 $K$,她想要求出每个连续的 $K$ 节车厢中最小的 ID。她有一本能够帮助执行计算的笔记本,但是这个笔记本相当小,并且 Bessie 的手写(蹄写?)字相当大。比方说,可能没有足够的空间记下所有 $N+1-K$ 个最小值。由于某些神秘的原因,Bessie 满足于当她算出最小数的时候向天哞出这些数,所以这个问题至少还不成问题。

列车马上就要来了!帮助 Bessie 在列车经过两次之后求出这 $N+1-K$ 个最小数,确保她有效地利用她有限的笔记本空间。她的笔记本被分为 $5500$ 个部分,方便起见编号为 $0\sim 5499$,每个部分的空间恰好能够记录一个在 $[-2^{31} , 2^{31}-1]$ 之间的整数。最初的时候,每个部分都记录着整数 $0$。

请帮助 Bessie 有效管理她有限的笔记本空间。

Solution

要求出多个区间最小值,如果没有空间限制,可以ST表/线段树解决

此时要求空间限制$O(\sqrt n)$,并且可以读入两遍数据

第一遍读入数据:将下标为$0,\sqrt n ,\sqrt{2n},\cdots ,n$的最小值算出,可以在读入数据时更新每个块的最小值,如果当前读入的位置是某个要求区间的右端点暴力扫所有块,时间复杂度$O(n)$,空间复杂度$O(\sqrt n)$

第二遍读入数据,将其他下标的最小值算出

事实:$i+1$的区间中最小值取值位置一定不在$i$的区间中最小值取值位置之前

那么对于左端点在同一个块内的所有最小值查询,最小值的取值位置在一个区间内,将这个区间分为两部分

第一部分:与左端点在同一个块内的,这些位置可能会随着窗口移动而从左侧移出窗口,这部分的值用单调队列维护

第二部分:与左端点不在同一个块,这些位置永远不会移出窗口,直接维护这一部分的最小值

若读入数据时若已经到了某个询问的右端点,应该立即回答

若已经读入到取值位置的区间的右端点,应该回答块内所有讯问

对于最后一个块特殊处理,暴力去做

时间复杂度$O(n)$,由于单调队列中至多$\sqrt n$个元素,空间复杂度$O(\sqrt n)$

#include"grader.h"
#include<algorithm>
using namespace std;
void helpBessie(int v){
    int cur=getCurrentCarIndex(),n=getTrainLength()-1,K=getWindowLength(),inf=0x7f7f7f7f,B=1000;
    if(!getCurrentPassIndex()){
        int i;
        if(!cur)for(int i=0;i*B<=n;i++)set(i,inf);
        if(v<get(cur/B))set(cur/B,v),set(cur/B+B,cur);
        for(i=get(5000);cur==n||cur==i*B+K-1;i++){
            if(i*B>n)break;
            int minn=inf,mnpos=0;
            for(int j=i;j<=(i*B+K-1)/B;j++){
                int temp=get(j);
                if(temp<minn)minn=temp,mnpos=get(j+B);
            }
            set(i+4000,mnpos);
        }
        if(cur<n)set(5000,i);
        else set(5000,0),set(5001,1);
    }
    else{
        int pos=get(5000),h=get(5001),t=get(5002),siz=1050;
        while(h<=t&&v<=get(t%siz))--t;
        ++t,set(t%siz,v),set(t%siz+siz,cur);
        for(;pos+K-1<=n;++pos){
            if(cur!=pos+K-1&&(pos/B==n/B||cur!=get(pos/B+4001)))break;
            while(h<=t&&get(h%siz+siz)<pos)++h;
            shoutMinimum(get(h%siz));
        }
        if(h<t&&cur/B>pos/B&&get((t-1)%siz+siz)/B>pos/B)--t;
        set(5000,pos),set(5001,h),set(5002,t);
    }
}
Train Tracking P

 

posted @ 2021-03-18 10:53  QDK_Storm  阅读(148)  评论(0编辑  收藏  举报