P7446 [Ynoi2007] rfplca
sol
考虑如何找 LCA,通常来说我们会使用倍增,然而这道题带修,因此倍增不可实现。
考虑对序列分块,每个点维护其父亲以及其最近的不与其在同一块中的祖先,散块重构是简单的,但貌似无法整块修改?不难发现,一个块被操作块长次后,其内每个点的父亲在块外了,因此每个整块前块长次操作暴力重构,后面直接维护 \(\sum x\) 这个标记,查询更新父亲即可。
令块长为 \(\sqrt n\),则复杂度为 \(O(n\sqrt n)\)。
想到整块修改的处理方式之后就没什么了,但整块修改这个维护方式对于我这种不特别擅长分块的蒟蒻来说可能还是没那么好想。
code
const int N=4e5+5,B=640;int n,m;
int a[N],b[N];
int L[B],R[B],id[N];ll sum[B];
int tim[B];inline void Main(){cin>>n>>m;rep(i,2,n)cin>>a[i];rep(i,1,(n-1)/B+1){L[i]=(i-1)*B+1;R[i]=min(i*B,n);rep(j,L[i],R[i]){id[j]=i;b[j]=a[j];if(b[j]>=L[i])b[j]=b[b[j]];}}int ans=0;rep(t,1,m){int o;cin>>o;if(o==1){int l,r;ll x;cin>>l>>r>>x;l^=ans,r^=ans,x^=ans;if(id[l]==id[r]){int bd=id[l];rep(i,L[bd],R[bd])a[i]=max(1ll,a[i]-sum[bd]);sum[bd]=0;rep(i,l,r)a[i]=max(1ll,a[i]-x);rep(i,L[bd],R[bd]){b[i]=a[i];if(b[i]>=L[bd])b[i]=b[b[i]];}}else{int lb=id[l],rb=id[r];rep(i,L[lb],R[lb])a[i]=max(1ll,a[i]-sum[lb]);rep(i,L[rb],R[rb])a[i]=max(1ll,a[i]-sum[rb]);sum[lb]=sum[rb]=0;rep(i,l,R[lb]){a[i]=max(1ll,a[i]-x);b[i]=a[i];if(b[i]>=L[lb])b[i]=b[b[i]];}rep(i,L[rb],R[rb]){if(i<=r)a[i]=max(1ll,a[i]-x);b[i]=a[i];if(b[i]>=L[rb])b[i]=b[b[i]];}rep(bd,lb+1,rb-1)if(++tim[bd]<B){rep(i,L[bd],R[bd]){b[i]=a[i]=max(1ll,a[i]-x);if(b[i]>=L[bd])b[i]=b[b[i]];}}else sum[bd]+=x;}}else{int u,v;cin>>u>>v;u^=ans,v^=ans;if(tim[id[u]]>=B)b[u]=max(1ll,a[u]-sum[id[u]]);if(tim[id[v]]>=B)b[v]=max(1ll,a[v]-sum[id[v]]);while(b[u]!=b[v])if(b[u]>b[v]){u=b[u];if(tim[id[u]]>=B)b[u]=max(1ll,a[u]-sum[id[u]]);}else {v=b[v];if(tim[id[v]]>=B)b[v]=max(1ll,a[v]-sum[id[v]]);}while(u!=v)if(u>v)u=max(1ll,a[u]-sum[id[u]]);else v=max(1ll,a[v]-sum[id[v]]);put(ans=u);}}
}