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

正题

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


题目大意

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


解题思路

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

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


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]);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值