题目:
题意:
我们有
n
n
n个点,
m
m
m组状态,每个状态都有一个起点和油量,从一点到另一点的耗油量等于距离的差
我们开车行走的规则为先一直想东走至不能再走,再向西一直走,一直反复
问每个状态最终车子会停留在哪里
分析:
我们先将所有点排序,然后做一遍前缀和
这样前缀和就满足单调性,可以开始二分乱搞
对于每个起点,我们总是可以二分找到当前油量能走到的最东点,往西走也是同理
但会出现一个小小的问题,我们会遇到一种反复横跳的离谱数据,这样会非常不爽
考虑当每次二分一个回合后我们找到的最东和最西点,是这以后能走到的最点,不可能存在走出的可能,要么区间一样,要么缩小,所以我们运用这点,对剩余油量判一下循环的次数,处理下就完事了
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<ctime>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
struct in{
int w,k;
}x[200005];
int s[200005],id[200005];
bool cmp(in a,in b) {return a.w<b.w;}
int main()
{
int n=read(),m=read();
for(int i=1;i<=n;i++) x[i].w=read(),x[i].k=i;
sort(x+1,x+1+n,cmp);
for(int i=2;i<=n;i++) s[i]=s[i-1]+x[i].w-x[i-1].w; s[0]=-2147483647/3;s[n+1]=2147483647/3;
for(int i=1;i<=n;i++) id[x[i].k]=i;
for(int i=1;i<=m;i++)
{
int k=read(),y=read(),tf=1; int f=id[k],L,R;
while(tf)
{
tf=0;
int l=f,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(s[mid]-s[f]<=y) l=mid+1;
else r=mid-1;
}
if(s[l]-s[f]<=y&&l!=f&&l<=n)
{
y-=s[l]-s[f];
f=l;
tf++;
}
else
if(s[l-1]-s[f]<=y&&l-1!=f)
{
y-=s[l-1]-s[f];
f=l-1;
tf++;
}
R=f;
l=1;r=f;
while(l<=r)
{
int mid=(l+r)>>1;
if(s[f]-s[mid]<=y) r=mid-1;
else l=mid+1;
}
if(s[f]-s[r]<=y&&r!=f&&r>0)
{
y-=s[f]-s[r];
f=r;
tf++;
}
else
if(s[f]-s[r+1]<=y&&r+1!=f)
{
y-=s[f]-s[r+1];
f=r+1;
tf++;
}
L=f;
if(tf==2)
{
if(y/(s[R]-s[L])>1)
{
if((y/(s[R]-s[L]))&1) f=R; else f=L;
y%=(s[R]-s[L]);
}
}
}
printf("%d\n",x[f].k);
}
return 0;
}