(分块)Holes CodeForces

题意

n(n≤105)个洞排成一条直线,第ii个洞有力量值ai,当一个球掉进洞ii时就会被立刻弹到i+ai,直到超出n。进行m(m105)次操作:

·修改第i个洞的力量值ai

·在洞xx上放一个球,问该球几次后被哪个洞弹飞出界。

思路

分块暴力,每个块内维护两个信息(块内DP可以求出):

①从当前位置跳出块内需要跳几次num[i]

②从当前块内跳出的下一个位置jump[i]

修改:

只需要将修改元素所在块内信息更新一次即可,单次时间复杂O(√n)

查询:

由起点i不停往下一个块跳jump[i],并且累计次数num[i],在最后一个块内暴力便利一遍就行了

#include<iostream>
#include<algorithm>
#include<cmath>
 using namespace std;
const int maxn=1e5+10;
int n,m,bl,bel[maxn],x,y;
int a[maxn],num[maxn],jump[maxn];
void update(int x)
{
	int fr=x*bl,to=fr+bl-1;if(to>n) to=n;
	for(int i=to;i>=fr;i--){
		if(a[i]+i>to){
			num[i]=1;
			jump[i]=a[i]+i;
		}
		else{
			num[i]=num[i+a[i]]+1;
			jump[i]=jump[i+a[i]];
		}
	}
}
void query(int x)
{
	int ans=0,i,pre;
	for(i=x;i<=n;i=jump[i])
		ans+=num[i],pre=i;
	while(pre+a[pre]<=n)
		pre+=a[pre];
	printf("%d %d
",pre,ans);
}
int main()
{
	scanf("%d%d",&n,&m);
	int op;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		num[i]=0;
		jump[i]=i;
	}
	bl=sqrt(n);
	for(int i=0;i<=n/bl;i++)
		update(i);
	while(m--){
		scanf("%d",&op);
		if(op==0){
			scanf("%d%d",&x,&y);
			a[x]=y;
			update(x/bl);
		}
		else{
			scanf("%d",&x);
			query(x);
		}
	}
	return 0;
}

  

 

 

原文地址:https://www.cnblogs.com/overrate-wsj/p/12170665.html