这是个挺平凡的 DS 题感觉。不知道为啥有 2800?
考虑对于一个区间,先算出最大的 (|s|)。那么贪心地,显然可以从 (l) 开始往后,每次找到最左边一个 keep 住 distance 的地方跳过去直到到 (r) 右边为止。
然后发现,(s) 中最右边一个位置一直到 (r) 都是可以当作 (s) 的最后一个的,也即最后一位的取值范围是一个区间。然后考虑倒数第二个位置的取值范围,左端点显然是原来的,右端点基于贪心是上一个区间的右端点往左跳。以此类推可以算出每个位置的取值范围。
稍微想想,每个区间显然不可能有 (k) 个,这说明区间们不相交;然后显然的,右端点就是把之前找左端点的那个过程反过来,从 (r) 往左跳,它们得出的个数显然都是最大的 (|s|),相等,于是左端点和右端点数量匹配。这两点证明了上面那个的合理性。
然后答案就是所有区间的个数和。那就是 (sum(r_i-l_i+1)),拆开来是 (sum r_i+sum(-l_i+1))。由于左端点和右端点的计算是独立的,于是可以分别计算。这个倍增随便搞搞就完事了。
#include<bits/stdc++.h>
using namespace std;
const int N=200000,LOG_N=20;
int n,m,qu;
int a[N+1];
int rit[N+1],lft[N+1];
int rit_to[N+1][LOG_N],rit_sum[N+1][LOG_N],lft_to[N+1][LOG_N],lft_sum[N+1][LOG_N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)scanf("%d",a+i);
int now=1;
for(int i=1;i<=n;i++){
while(now<=n&&a[now]-a[i]<m)now++;
rit[i]=now;
}
rit[n+1]=n+1;
for(int i=n+1;i;i--){
rit_to[i][0]=rit[i],rit_sum[i][0]=-rit[i]+1;
for(int j=1;j<LOG_N;j++)
rit_to[i][j]=rit_to[rit_to[i][j-1]][j-1],
rit_sum[i][j]=rit_sum[i][j-1]+rit_sum[rit_to[i][j-1]][j-1];
}
now=n;
for(int i=n;i;i--){
while(now&&a[i]-a[now]<m)now--;
lft[i]=now;
}
lft[0]=0;
for(int i=0;i<=n;i++){
lft_to[i][0]=lft[i],lft_sum[i][0]=lft[i];
for(int j=1;j<LOG_N;j++)
lft_to[i][j]=lft_to[lft_to[i][j-1]][j-1],
lft_sum[i][j]=lft_sum[i][j-1]+lft_sum[lft_to[i][j-1]][j-1];
}
cin>>qu;
while(qu--){
int l,r;
scanf("%d%d",&l,&r);
int ans=0;
now=l;
ans+=-now+1;
for(int i=LOG_N-1;~i;i--)if(rit_to[now][i]<=r)ans+=rit_sum[now][i],now=rit_to[now][i];
now=r;
ans+=now;
for(int i=LOG_N-1;~i;i--)if(lft_to[now][i]>=l)ans+=lft_sum[now][i],now=lft_to[now][i];
printf("%d
",ans);
}
return 0;
}