[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中所含沙子的克数。

$1leq Xleq 10^9$

$1leq Kleq 10^5$

$1leq Qleq 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
",ans);
25             t2++;
26         }
27     }
28     return 0;
29 }
原文地址:https://www.cnblogs.com/dcdcbigbig/p/9501886.html