P3203-[HNOI2010]弹飞绵羊【分块】

版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/84670709

正题

评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P3203


题目大意

n n 个装置。到第 i i 个装置会被往前弹 a i a_i 个。
两种操作
修改 a i a_i 和询问从 i i 出发要多少次弹射可以弹出去。


解题思路

分块。对于每个点,维护要多少步弹出该块和弹出去后弹到哪里。
询问就直接根据两个数据,修改就直接重构整个块。

时间复杂度: O ( n n ) O(n\sqrt n)


code

#include<cstdio>
#include<cmath>
#define N 200010
#define T 500
using namespace std;
int n,m,x,t,a[N],L[T],R[T],step[N],to[N],pos[N];
void pre_work()//预处理
{
	for(int i=1;i<=t;i++)//块边界
	{
		L[i]=(i-1)*t+1;
		R[i]=i*t;
	}
	if(R[t]!=n) t++,L[t]=R[t-1]+1,R[t]=n;
	for(int i=1;i<=t;i++)
	  for(int j=R[i];j>=L[i];j--)
	  {
	      if(j+a[j]<=R[i]) step[j]=step[j+a[j]]+1,to[j]=to[j+a[j]];
	      else step[j]=1,to[j]=j+a[j];
	      pos[j]=i;
	  }//初始数据
}
int ask(int x)//询问
{
	int ans=0;
	while(x<=n)
	  ans+=step[x],x=to[x];
	return ans;
}
void change(int i)//重构块
{
	for(int j=R[i];j>=L[i];j--)
	  if(j+a[j]<=R[i]) step[j]=step[j+a[j]]+1,to[j]=to[j+a[j]];
	  else step[j]=1,to[j]=j+a[j];
}
int main()
{
	scanf("%d",&n);
	t=sqrt(n);
	for(int i=1;i<=n;i++)
	  scanf("%d",&a[i]);
	pre_work();
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&x);
		if(x==1)
		{
			scanf("%d",&x);x++;
			printf("%d\n",ask(x));
		}
		else{
			scanf("%d",&x);x++;
			scanf("%d",&a[x]);
			change(pos[x]);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/84670709