[arc082f]sandglass
Description
有一个沙漏由两个上下相通玻璃球A和B构成,这两个玻璃球都含有一定量的沙子,我们暂且假定AB中位于上方的玻璃球的为U,下方的玻璃球为L,则除非U中没有沙子,否则每秒钟都会有1克沙子从U掉入L。
在第0个时刻,A中有a克沙子(总共有X克沙子),且U为A,L为B(即A上B下)。在r1,r2,...,rK这些时刻,我们将倒转整个沙漏,使得原来的U变成L,原来的L变成U。
对于翻转操作,t时刻是指从第0个时刻起经过t秒后的时刻,我们可以将翻转沙漏的操作看做瞬间完成的。
现在有Q次询问,每一次询问会给定一对非负整数,求a=ai,第ti时刻,A中所含沙子的克数。
$1\leq X\leq 10^9$
$1\leq K\leq 10^5$
$1\leq Q\leq 10^5$
Input
第一行一个正整数X
第二行一个正整数K
第三行K个整数,表示r1,r2,...,rk
接下来一行一个正整数Q
接下来Q行,每行两个非负整数,分别表示每次次询问的(ti,ai)
Output
一共Q行
对于每次询问,输出一行一个非负整数表示答案
题解:
(别问我为什么拖了两天)
这个函数要么斜率为1上升,要么斜率为-1下降,碰到上下边界就是一条直线,双指针同时维护翻转和询问,不同的a等同于将图像上下平移,大力模拟即可;
时间复杂度O(玄学,能过)
貌似有线段树做法?我不会啊qwq
代码:
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<cmath>
5 using namespace std;
6 int X,k,q,t1=0,t2=1,f=-1,maxn,minn=0,now=0,p=0,ans,t[100001],a[100001],r[100001];
7 int main(){
8 scanf("%d%d",&X,&k);
9 for(int i=1;i<=k;i++)scanf("%d",&r[i]);
10 scanf("%d",&q);
11 for(int i=1;i<=q;i++)scanf("%d%d",&t[i],&a[i]);
12 maxn=X;
13 while(t2<=q){
14 if(t[t2]>r[t1+1]&&t1<k){
15 t1++;
16 now=f*(r[t1]-r[t1-1]);
17 minn=max(0,min(X,minn+now));
18 maxn=max(0,min(X,maxn+now));
19 p+=now;
20 f*=-1;
21 }else{
22 ans=max(minn,min(maxn,a[t2]+p));
23 ans=max(0,min(X,ans+f*(t[t2]-r[t1])));
24 printf("%d\n",ans);
25 t2++;
26 }
27 }
28 return 0;
29 }