Bounce 弹飞绵羊

某天,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

image

怎么说呢,我就是菜
一开始听张云杰讲,感觉自己会了,就开搞了
以下是张云杰的讲解:
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);
		}
	}
}

posted @   shaoyufei  阅读(13)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示