ARC082 D - Sandglass
Solution
这题睡觉的时候 想了挺久的。
一段时间 Δ t \Delta t Δt内要么是让 x + Δ t x+\Delta t x+Δt对 X X X取 m i n min min,要么是让 x − Δ t x-\Delta t x−Δt对 0 0 0取 m a x max max。
如果没有对边界取 m a x / m i n max/min max/min,就是一个单纯的前缀和了。而加上对边界取 m a x / m i n max/min max/min,对于没有撞到过边界的还是一个和之前一样的前缀和,但如果撞到过边界答案就会改变。
我们发现有这样一个性质:
对于
[
0
,
X
]
[0,X]
[0,X]的这一个区间经过若干次操作之后,会存在一个前缀和
0
0
0贴贴(指之后的值都和
0
0
0一样),存在一个后缀和
X
X
X贴贴(指之后的值都和
X
X
X一样)。
这个性质的来源可以通过下列过程得到:
- 初始有一个区间 [ L , R ] = [ 0 , X ] [L,R]=[0,X] [L,R]=[0,X]表示还没有和 0 0 0或 X X X贴贴的区间。
- 若这一次是减的, [ L ′ , R ′ ] = [ L − Δ t , R − Δ t ] [L',R']=[L-\Delta t,R-\Delta t] [L′,R′]=[L−Δt,R−Δt],且 L ′ < 0 L'<0 L′<0了,那么当前的 [ L ′ , 0 ) [L',0) [L′,0)这一段值就和 0 0 0贴贴了,也就是说,初始区间中与 0 0 0贴贴的一部分前缀的长度增加 − L ′ -L' −L′。
- 若这一次是加的, [ L ′ , R ′ ] = [ L + Δ t , R + Δ t ] [L',R']=[L+\Delta t,R+\Delta t] [L′,R′]=[L+Δt,R+Δt],且 R ′ > X R'>X R′>X了,那么当前的 ( X , R ′ ] (X,R'] (X,R′]这一段值就和 0 0 0贴贴了,也就是说,初始区间中与 0 0 0贴贴的一部分前缀的长度增加 R ′ − X R'-X R′−X。
- 注:这里为了方便不会让正好等于 0 , X 0,X 0,X的数和 0 , X 0,X 0,X贴贴。
- (是不是和 N O I P 2020 T 4 NOIP2020\;T4 NOIP2020T4的方法有异曲同工之妙?)
然后我们发现上述过程我们是可以直接模拟的,于是可以求出 a i , t a i a_i,ta_i ai,tai表示 [ 0 , a i ) [0,a_i) [0,ai)最早在 t a i ta_i tai时刻与 0 0 0贴贴,同样 b i , t b i b_i,tb_i bi,tbi表示与 X X X贴贴的我们也能求出来。
然后我们可以预处理
0
0
0的变化和
X
X
X的变化。
对于
(
x
,
y
)
(x,y)
(x,y)这个询问,如果
y
y
y在
x
x
x时刻之前和
0
0
0或
X
X
X贴贴了,那就按照
0
/
X
0/X
0/X之前预处理的答案算即可;如果没有,那么就表示
y
y
y在
x
x
x时刻之前从来没有撞到过
0
0
0或
X
X
X的边界,因此再求一个前缀和计算就可以了。
时间复杂度 O ( n l g n ) O(nlgn) O(nlgn)。
Code
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second
using namespace std;
template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }
typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;
const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
int f=1,x=0; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
return x*f;
}
int T[MAXN],numa=0,numb=0,s[MAXN],p0[MAXN],px[MAXN];
PR a[MAXN],b[MAXN];
signed main()
{
int X=read(),n=read();
for (int i=1;i<=n;i++) T[i]=read(); T[n+1]=INF+INF;
int L=0,R=X;
for (int i=1;i<=n+1;i++)
{
int t=T[i]-T[i-1];
if (i&1)
{
L-=t,R-=t;
if (R<0) { numa++,a[numa]=MP(a[numa-1].fi+R-L+1,i); break; }
else if (L<0) numa++,a[numa]=MP(a[numa-1].fi-L,i),L=0;
}
else
{
L+=t,R+=t;
if (L>X) { numb++,b[numb]=MP(b[numb-1].fi+R-L+1,i); break; }
else if (R>X) numb++,b[numb]=MP(b[numb-1].fi+R-X,i),R=X;
}
}
p0[0]=0,px[0]=X;
for (int i=1;i<=n+1;i++)
{
int t=T[i]-T[i-1];
if (i&1) s[i]=s[i-1]-t,p0[i]=max(p0[i-1]-t,0),px[i]=max(px[i-1]-t,0);
else s[i]=s[i-1]+t,p0[i]=min(p0[i-1]+t,X),px[i]=min(px[i-1]+t,X);
}
int Case=read();
while (Case--)
{
int x=read(),y=read(),p=lower_bound(T+1,T+n+2,x)-T-1,ans;
if (y<a[numa].fi)
{
int t=lower_bound(a+1,a+numa+1,MP(y,-1))-a;
if (T[a[t].se]>x) ans=y+s[p]+(x-T[p])*((p&1)?1:-1);
else ans=p0[p]+(x-T[p])*((p&1)?1:-1);
}
else if (X-y<b[numb].fi)
{
int t=lower_bound(b+1,b+numb+1,MP(X-y,-1))-b;
if (T[b[t].se]>x) ans=y+s[p]+(x-T[p])*((p&1)?1:-1);
else ans=px[p]+(x-T[p])*((p&1)?1:-1);
}
upmin(ans,X),upmax(ans,0);
printf("%d\n",ans);
}
return 0;
}