校内测 10.29 T3 走亲戚【二分】


题目:

传送门


题意:

我们有 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值