某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装
置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置
起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
输入格式
第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1
接下来一行有n个正整数,依次为那n个装置的初始弹力系数。
第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
输出格式
对于每个i=1的情况,你都要输出一个需要的步数,占一行。
样例
样例输入
4
1 2 1 1
3
1 1
2 1 1
1 1
样例输出
2
3
怎么说呢,我就是菜
一开始听张云杰讲,感觉自己会了,就开搞了
以下是张云杰的讲解:
1.如果纯暴力模拟,那么查询就就会出锅
2.预先简单便利一遍,拿数组存一下,但很显然,修改就会出锅
3.所以要拿分块去解决2中的问题,怎么搞呢,修改出锅是因为会影响到前面的步数,但如果分块的话,就可以把这个影响减小到当前分块
分块
用一个数组存当前位置到下一个块的最短步数,再用一个数组存到跳到下个区块对应位置的下标,这样修改的话就仅用修改当前区块的状态
然后…………
void add(int x,int z){
int p=vis[x];
int k=x;
a[x]=z;step[x]=0;
while(k<=r[p]){
step[x]++;
k=k+a[k];
}
last[x]=k;
}
他就寄了,每回都差几个数
后面想了一下,发现不只是当前位置会改变,而是当前区块的所有经过它的点都会改变,所以就成了这样
void add(int x,int z){
int p=vis[x];
int k=x;
a[x]=z;step[x]=0;
for(int i=l[p];i<=x;i++){
int k1=i;step[i]=0;
while(k1<=r[p]){
step[i]++;
k1=k1+a[k1];
}
last[i]=k1;
}
}
他就T了
后面询问了peppa pig(快说谢谢pig),虽然说的牛头不对马嘴,但告诉了我一个关键点,那就是DP
后面就简单推了一下(不会写公式)
if(j+a[j]>r[i]){step[j]=1;last[j]=j+a[j];}
else {
step[j]=step[j+a[j]]+1;
last[j]=last[j+a[j]];
}
很显然,前面的状态只能由后面转移过来,所以要倒叙
然后就没了
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=360010;
typedef long long ll;
ll a[N];
int l[N],r[N];
int vis[N];
ll step[N];
ll last[N];
ll lazy[N];
int n,m,b;
string s;
int x,y,z;
void div(){
int sq=sqrt(n);
for(int i=1;i<=sq;i++){
l[i]=(i-1)*sq+1;
r[i]=i*sq;
}
if(r[sq]<n){
sq++;
l[sq]=r[sq-1]+1;
r[sq]=n;
}
for(int i=sq;i>=1;i--){
for(int j=r[i];j>=l[i];j--){
vis[j]=i;
if(j+a[j]>r[i]){step[j]=1;last[j]=j+a[j];}
else {
step[j]=step[j+a[j]]+1;
last[j]=last[j+a[j]];
}
}
}
}
void add(int x,int z){
int p=vis[x];
a[x]=z;
for(int i=r[p];i>=l[p];i--){
step[i]=0;
if(i+a[i]>r[p]){step[i]=1;last[i]=i+a[i];}
else{
step[i]=step[i+a[i]]+1;
last[i]=last[i+a[i]];
}
}
}
ll query(int x){
int k=x;long long ans=0;
while(k<=n){
ans+=step[k];
k=last[k];
}
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
div();
cin>>m;
for(int i=1;i<=m;i++){
cin>>z;
if(z==1){
cin>>b;
cout<<query(b+1)<<endl;
}
else {
cin>>b>>y;
add(b+1,y);
}
}
}