正解是LCT但我不会呀蛤蛤蛤蛤蛤
(分块我也没想出来
把区间分成根n个块,每个块内记录两个东西,就是该位置弹多少次能够弹出这个块,以及该位置弹到最后弹出去了之后能够弹到哪里。
然后查询就一个块一个块的跳,修改就暴力重构这个块。
#include<cstdio> #include<algorithm> #include<cctype> #include<cstring> #include<cmath> #include<cstdlib> #define maxn 200010 #define sqtn 450 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int q[maxn]; int s[maxn]; int le[maxn],ri[maxn]; struct Block{ int out[sqtn],nxt[sqtn]; }d[sqtn]; void update(int i){ Block &o=d[i]; for(int j=ri[i];j>=le[i];--j){ int x=j-le[i]+1; o.nxt[x]=j+q[j]; if(o.nxt[x]>ri[i]) o.out[x]=1; else{ o.out[x]=o.out[o.nxt[x]-le[i]+1]+1; o.nxt[x]=o.nxt[o.nxt[x]-le[i]+1]; } } } int main(){ int n=read();int sqt=sqrt(n),blo=0; for(int i=1;i<=n;++i){ q[i]=read(); s[i]=(i-1)/sqt+1; if(s[i]>blo) blo=s[i]; ri[s[i]]=i; } for(int i=n;i>=1;--i) le[s[i]]=i; for(int i=1;i<=blo;++i) update(i); int m=read(); for(int i=1;i<=m;++i){ int opt=read(),x=read()+1; if(opt==1){ int pos=x,ans=0; while(pos<=n){ ans+=d[s[pos]].out[pos-le[s[pos]]+1]; pos=d[s[pos]].nxt[pos-le[s[pos]]+1]; } printf("%d ",ans); } else{ int y=read(); q[x]=y; update(s[x]); } } return 0; }