版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/83278842
题意:
给你
个坐标,要求每次移动不超过
,并且每次移动后一定要到这
个坐标中的某一个。有
次询问,每次询问一对点
,求从
到
最少移动几次。
题解:
首先我们可以用一个two pointer在O(n)的时间内算出以每个点为起点走不超过
的距离最多走到哪个点。感觉网上好多都说要二分,但是我感觉二分还没有two pointer好写,而且跑得还慢。求完只后我们可以对刚才的数组倍增,求出每个点操作
步最多到达的编号是多少。这样对于每次询问,从
到
和从
到
是等价的,所以我们设
。我们从
先跳到小于
的可以跳到的最后一个点,然后再跳一次就能跳到
了,于是就可以用倍增每次
的复杂度来回答询问了。最终复杂度
。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,q,a[100010],f[100010][21],l,r;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
scanf("%d",&l);
r=1;
for(int i=1;i<=n;++i)
{
while(a[r+1]-a[i]<=l&&r+1<=n)
++r;
f[i][0]=r;
}
for(int i=n;i>=1;--i)
{
for(int j=1;j<=20;++j)
f[i][j]=f[f[i][j-1]][j-1];
}
scanf("%d",&q);
for(int i=1;i<=q;++i)
{
int x,y,ans=0;
scanf("%d%d",&x,&y);
if(x>y)
swap(x,y);
for(int j=20;j>=0;--j)
{
if(f[x][j]<y)
{
x=f[x][j];
ans+=(1<<j);
}
}
ans+=1;
printf("%d\n",ans);
}
return 0;
}