题目:点击打开链接
思路:
利用分块思想。
划分块左右界的方式是固定的,加俩数组即可。
en[i]表示跳出i所在块后的位置,ne[i]表示跳出i所在的块还有几步。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int a[maxn],en[maxn],ne[maxn],l,r,n,m,block,p;
int query(int pos){
int ans=0;
while(pos<=n){
ans+=ne[pos];
pos=en[pos];
}
return ans;
}
void update(int pos,int x){
a[pos]=x;
l=(pos/p)*p+1; //找出该块最左边的下标
r=l+p-1;
if(pos%p==0) l-=p,r-=p; //如果是块的最后一个如此处理
for(int i=pos;i>=l;i--){
int u=i+a[i];
if(u>r){
en[i]=u;
ne[i]=1;
}
else{
en[i]=en[u];
ne[i]=ne[u]+1;
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
block=sqrt(n),p=n/block; //有几块,一块有几个
if(n%p) block++;
for(int i=1;i<=block;i++){
l=(i-1)*p+1;
r=min(i*p,n);
for(int j=r;j>=l;j--){ //倒着找,可以使已经找到的赋给前面
int u=j+a[j];
if(u>r){
en[j]=u; //表示跳出i所在块的位置
ne[j]=1; //表示距离跳出i所在的块还有几步
}
else{
en[j]=en[u];
ne[j]=ne[u]+1;
}
}
}
scanf("%d",&m);
int flg,pos,x;
for(int i=1;i<=m;i++){
scanf("%d",&flg);
if(flg==1){
scanf("%d",&pos);
printf("%d\n",query(pos+1));
}
else{
scanf("%d%d",&pos,&x);
update(pos+1,x);
}
}
return 0;
}