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); } }