【題解】Loj139 樹鏈剖分
阿新 • • 發佈:2021-10-29
\(\text{Solution:}\)
先不考慮換根,那其他的就很板子。
考慮換根的影響,首先對在路徑上的操作沒有影響,唯一有影響的就是子樹操作。
考慮直接先在 \(root=1\) 的情況下樹剖,然後直接在上面分類討論。
如果當前根就是要修改的點,那就直接全域性修改;
如果當前根在我要修改的子樹之外,那就直接修改這個子樹;
否則,我們畫圖可以發現,把根轉上去之後,\(u\) 的子樹就是全樹去掉 \((u,root)\) 路徑上深度最淺的點的子樹。
由於加法有逆元,所以直接減回去即可。
總複雜度 \(O(n\log^2 n),\) 找點需要再來一個倍增。
#include<bits/stdc++.h> using namespace std; typedef double db; #define int long long const int mod=1e9+7; const db eps=1e-14; inline int Max(int x,int y){return x>y?x:y;} inline int Min(int x,int y){return x<y?x:y;} inline db Max(db x,db y){return x-y>eps?x:y;} inline db Min(db x,db y){return x-y<eps?x:y;} inline int Add(int x,int y,int M=mod){return (x+y)%M;} inline int Mul(int x,int y,int M=mod){return 1ll*x*y%M;} inline int Dec(int x,int y,int M=mod){return (x-y+M)%M;} inline int Abs(int x){return x<0?-x:x;} inline int read(){ int s=0,w=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();} while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();} return s*w; } inline void write(int x){ if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); } inline int qpow(int x,int y){ int res=1; while(y){ if(y&1)res=Mul(res,x); x=Mul(x,x);y>>=1; } return res; } typedef pair<int,int> pr; #define fi first #define se second #define mk make_pair #define pb emplace_back #define poly vector<int> const int N=2e5+10; namespace SGT{ int ls[N],rs[N],node,tag[N],sum[N]; inline void pushup(int x){sum[x]=sum[ls[x]]+sum[rs[x]];} inline void pushdown(int x,int l,int r){ if(tag[x]!=0){ int mid=(l+r)>>1; int p=tag[x]; tag[ls[x]]+=p; tag[rs[x]]+=p; sum[ls[x]]+=p*(mid-l+1); sum[rs[x]]+=p*(r-mid); tag[x]=0; } } void change(int x,int L,int R,int l,int r,int v){ if(L>=l&&R<=r){ tag[x]+=v; sum[x]+=(R-L+1)*v; return; } pushdown(x,L,R); int mid=(L+R)>>1; if(l<=mid)change(ls[x],L,mid,l,r,v); if(mid<r)change(rs[x],mid+1,R,l,r,v); pushup(x); } int query(int x,int L,int R,int l,int r){ if(L>=l&&R<=r)return sum[x]; int mid=(L+R)>>1,ans=0; pushdown(x,L,R); if(l<=mid)ans=query(ls[x],L,mid,l,r); if(mid<r)ans+=query(rs[x],mid+1,R,l,r); return ans; } } namespace Refined_heart{ using namespace SGT; const int SN=21; int a[N],pa[N],n,m,dfstime,rt; int dep[N],top[N],rk[N],id[N]; int head[N],tot,son[N],siz[N]; struct E{int nxt,to;}e[N]; int root,f[N][SN]; void build(int &x,int l,int r){ x=++node;tag[x]=0; if(l==r){ sum[x]=a[rk[l]]; return; } int mid=(l+r)>>1; build(ls[x],l,mid); build(rs[x],mid+1,r); pushup(x); } inline void link(int x,int y){ e[++tot]=(E){head[x],y}; head[x]=tot; } void dfs1(int x,int fa){ dep[x]=dep[fa]+1; siz[x]=1;pa[x]=fa; f[x][0]=fa; for(int i=1;i<SN;++i)f[x][i]=f[f[x][i-1]][i-1]; for(int i=head[x];i;i=e[i].nxt){ int j=e[i].to; if(j==fa)continue; dfs1(j,x); siz[x]+=siz[j]; if(siz[j]>siz[son[x]])son[x]=j; } } void dfs2(int u,int t){ top[u]=t; rk[id[u]=++dfstime]=u; if(!son[u])return; dfs2(son[u],t); for(int i=head[u];i;i=e[i].nxt){ int j=e[i].to; if(j==pa[u]||j==son[u])continue; dfs2(j,j); } } int LCA(int x,int y){ while(top[x]!=top[y]){ if(dep[x]<dep[y])swap(x,y); x=pa[top[x]]; } if(dep[x]>dep[y])swap(x,y); return x; } int findpoint(int ac,int now){ for(int i=SN-1;~i;--i)if(dep[f[now][i]]>dep[ac])now=f[now][i]; return now; } void chain(int x,int y,int opt,int v=0){ int ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); if(opt){ ans+=query(rt,1,n,id[top[x]],id[x]); x=pa[top[x]]; } else{ change(rt,1,n,id[top[x]],id[x],v); x=pa[top[x]]; } } if(dep[x]<dep[y])swap(x,y); if(opt)ans+=query(rt,1,n,id[y],id[x]),write(ans),putchar('\n'); else change(rt,1,n,id[y],id[x],v); } void solve(){ n=read(); for(int i=1;i<=n;++i)a[i]=read(); for(int i=2;i<=n;++i)pa[i]=read(); for(int i=1;i<=n;++i)link(pa[i],i),link(i,pa[i]); dfs1(1,0);dfs2(1,1);build(rt,1,n); m=read();root=1; for(int i=1;i<=m;++i){ int opt=read(); if(opt==1){ int u=read(); root=u; } if(opt==2){ int u=read(),v=read(),val=read(); chain(u,v,0,val); } if(opt==3){ int u=read(),k=read(); if(u!=root&&LCA(u,root)==u){ change(rt,1,n,1,n,k); int pos=findpoint(u,root); change(rt,1,n,id[pos],id[pos]+siz[pos]-1,-k); } else if(u==root)change(rt,1,n,1,n,k); else change(rt,1,n,id[u],id[u]+siz[u]-1,k); } if(opt==4){ int u=read(),v=read(); chain(u,v,1); } if(opt==5){ int u=read();int ans=0; if(u!=root&&LCA(u,root)==u){ ans+=query(rt,1,n,1,n); int pos=findpoint(u,root); ans-=query(rt,1,n,id[pos],id[pos]+siz[pos]-1); } else if(u==root)ans=query(rt,1,n,1,n); else ans=query(rt,1,n,id[u],id[u]+siz[u]-1); write(ans);putchar('\n'); } } } } signed main(){ // freopen("in.txt","r",stdin); Refined_heart::solve(); return 0; }