【HNOI2010】弹飞绵羊 题解(分块)
前言:其实这个题是用LCT做的,但蒟蒻因为太弱了,只会分块QAQ。
-----------------------------
题目大意:给定$n$个装置,每个装置有弹力系数$k_i$,即在这个位置上会被弹到$i+k_i$。现在有两个操作:1.修改某个弹力装置的弹力系数。2.问从$x$开始,弹几次后所处位置大于$n$。
预处理在每个点需要被弹飞的次数$sum[i]$和到达的下一个点$out[i]$。然后进行分块。修改的时候只需要在所在块内的$sum$和$out$即可。
每次询问和修改的时间复杂度都是$O(\sqrt n)$。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=200005; int out[maxn],sum[maxn],num[maxn]; int n,m,block,tot; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } inline int getpos(int x) { return (x-1)/block+1; } inline void work(int l,int r) { for (int i=r;i>=l;i--) { if (i+num[i]>getpos(i)*block) sum[i]=1,out[i]=i+num[i]; else sum[i]=sum[i+num[i]]+1,out[i]=out[i+num[i]]; } } int main() { n=read();block=sqrt(n); tot=n/block;if (n%block) tot++; for (int i=1;i<=n;i++) num[i]=read(); work(1,n); m=read(); for (int i=1;i<=m;i++) { int flag=read(),y=read()+1; if (flag==1) { int ans=sum[y],x=out[y]; for (int j=getpos(y);j<=tot&&x<=n;j++) ans+=sum[x],x=out[x]; printf("%d\n",ans); } else{ int z=read();num[y]=z; work((getpos(y)-1)*block+1,getpos(y)*block); } } return 0; }