ARC082 D - Sandglass
Solution
这题睡觉的时候 想了挺久的。
一段时间Δt\Delta tΔt内要么是让x+Δtx+\Delta tx+Δt对XXX取minminmin,要么是让x−Δtx-\Delta tx−Δt对000取maxmaxmax。
如果没有对边界取max/minmax/minmax/min,就是一个单纯的前缀和了。而加上对边界取max/minmax/minmax/min,对于没有撞到过边界的还是一个和之前一样的前缀和,但如果撞到过边界答案就会改变。
我们发现有这样一个性质:
对于[0,X][0,X][0,X]的这一个区间经过若干次操作之后,会存在一个前缀和000贴贴(指之后的值都和000一样),存在一个后缀和XXX贴贴(指之后的值都和XXX一样)。
这个性质的来源可以通过下列过程得到:
- 初始有一个区间[L,R]=[0,X][L,R]=[0,X][L,R]=[0,X]表示还没有和000或XXX贴贴的区间。
- 若这一次是减的,[L′,R′]=[L−Δt,R−Δt][L',R']=[L-\Delta t,R-\Delta t][L′,R′]=[L−Δt,R−Δt],且L′<0L'<0L′<0了,那么当前的[L′,0)[L',0)[L′,0)这一段值就和000贴贴了,也就是说,初始区间中与000贴贴的一部分前缀的长度增加−L′-L'−L′。
- 若这一次是加的,[L′,R′]=[L+Δt,R+Δt][L',R']=[L+\Delta t,R+\Delta t][L′,R′]=[L+Δt,R+Δt],且R′>XR'>XR′>X了,那么当前的(X,R′](X,R'](X,R′]这一段值就和000贴贴了,也就是说,初始区间中与000贴贴的一部分前缀的长度增加R′−XR'-XR′−X。
- 注:这里为了方便不会让正好等于0,X0,X0,X的数和0,X0,X0,X贴贴。
- (是不是和NOIP2020T4NOIP2020\;T4NOIP2020T4的方法有异曲同工之妙?)
然后我们发现上述过程我们是可以直接模拟的,于是可以求出ai,taia_i,ta_iai,tai表示[0,ai)[0,a_i)[0,ai)最早在taita_itai时刻与000贴贴,同样bi,tbib_i,tb_ibi,tbi表示与XXX贴贴的我们也能求出来。
然后我们可以预处理000的变化和XXX的变化。
对于(x,y)(x,y)(x,y)这个询问,如果yyy在xxx时刻之前和000或XXX贴贴了,那就按照0/X0/X0/X之前预处理的答案算即可;如果没有,那么就表示yyy在xxx时刻之前从来没有撞到过000或XXX的边界,因此再求一个前缀和计算就可以了。
时间复杂度O(nlgn)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 secondusing 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;
}