LCT裸题,之后填坑打一下
分块做法:每个点存几次出块以及出块的位置,问的时候直接暴力跳就vans了
首先思考最普通的模拟,发现可以O(n)路径压缩,O(1)的查询,但是需要修改就变成了O(n^2)的修改,于是考虑分块,记录一下每个点跳出该点所在的块的步数,也就是在每块内进行路径压缩,还有记录每个点跳出块后到达的点,同样可以块内路径压缩完成,这样就变成了O(sqrt(n))的修改和查询,但是预处理是O(n*sqrt(n))的,虽然可以过,但是LCT更快
时间复杂度:O((m+n)sqrt(n))
#include<bits/stdc++.h>using namespace std; const int N=2e5+7; int n,m,pos[N],a[N],times[N],end[N],L[N],R[N]; void calc(int l,int r){ for(int i=r;i>=l;i--){ if(i+a[i]>=R[pos[i]]){ times[i]=1; end[i]=i+a[i]; } else { times[i]=times[i+a[i]]+1; end[i]=end[i+a[i]]; } } } int main(){ cin>>n; int t=sqrt(n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]; pos[i]=(i-1)/t+1; } cin>>m; 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; } calc(1,n); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d",&x,&y); y++; if(x==1){ int ans=0; while(y<=n){ ans+=times[y]; y=end[y]; } printf("%d\n",ans); } else { scanf("%d",&z); a[y]=z; calc(L[pos[y]],R[pos[y]]); } } return 0; }