樹鏈剖分筆記
阿新 • • 發佈:2022-03-05
1.將一棵樹轉化成一個序列
2.樹中路徑轉化成logn段連續區間
重兒子
重邊
重鏈:對於輕兒子,重鏈自它起始
重兒子在它父節點的重鏈上
dfs中優先遍歷重兒子 ,保證重鏈上所有點的編號是連續的
定理:樹中任意一條路徑均可拆分成O(logn)個重鏈(即為logn個連續區間)
#include <iostream> #include <cstring> #include <algorithm> typedef long long LL; using namespace std; const int N = 1e5+10,M=2e5+10; int n,m; int h[N],w[N],e[M],ne[M],idx; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int dep[N],sz[N],son[N],fa[N],p[N]; int dfn[N],wt[N],cnt; void dfs1(int u,int f,int d){ dep[u]=d; sz[u]=1; fa[u]=f; for(int i=h[u];~i;i=ne[i]){ int k=e[i]; if(k==f)continue; dfs1(k,u,d+1); sz[u]+=sz[k]; if(sz[k]>sz[son[u]])son[u]=k; } } void dfs2(int u,int f){ p[u]=f; dfn[u]=++cnt; wt[cnt]=w[u]; if(!son[u])return ; dfs2(son[u],f); for(int i=h[u];~i;i=ne[i]){ int k=e[i]; if(k==fa[u])continue; if(k==son[u])continue; dfs2(k,k); } } struct Node{ int l,r; LL sum,add; }tr[4*N]; void pu(int u){ tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum; } void pd(int u){ Node &root=tr[u],&left=tr[u<<1],&right=tr[u<<1|1]; if(root.add){ left.add+=root.add,right.add+=root.add; left.sum+=(LL)(left.r-left.l+1)*root.add; right.sum+=(LL)(right.r-right.l+1)*root.add; root.add=0; } } void build(int u,int l,int r){ tr[u]={l,r,0,0}; if(l==r){ tr[u].sum=wt[l]; return ; } int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pu(u); } void modify(int u,int l,int r,int k){ if(tr[u].l>=l&&tr[u].r<=r){ tr[u].sum+=(LL)(tr[u].r-tr[u].l+1)*k; tr[u].add+=k; return ; } pd(u); int mid=tr[u].l+tr[u].r>>1; if(l<=mid)modify(u<<1,l,r,k); if(r>mid)modify(u<<1|1,l,r,k); pu(u); } LL query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r)return tr[u].sum; pd(u); int mid=tr[u].l+tr[u].r>>1; LL res=0; if(l<=mid)res+=query(u<<1,l,r); if(r>mid)res+=query(u<<1|1,l,r); return res; } void add_path(int u,int v,int k){ while(p[u]!=p[v]){ if(dep[p[u]]<dep[p[v]])swap(u,v); modify(1,dfn[p[u]],dfn[u],k); u=fa[p[u]]; } if(dep[u]<dep[v])swap(u,v); modify(1,dfn[v],dfn[u],k); } void add_tree(int u,int k){ modify(1,dfn[u],dfn[u]+sz[u]-1,k); } LL query_path(int u,int v){ LL res=0; while(p[u]!=p[v]){ if(dep[p[u]]<dep[p[v]])swap(u,v); res+=query(1,dfn[p[u]],dfn[u]); u=fa[p[u]]; } if(dep[u]<dep[v])swap(u,v); res+=query(1,dfn[v],dfn[u]); return res; } LL query_tree(int u){ return query(1,dfn[u],dfn[u]+sz[u]-1); } int main() { ios::sync_with_stdio(0); memset(h, -1, sizeof h); cin>>n; for(int i=1;i<=n;i++)cin>>w[i]; for(int i=1;i<n;i++){ int a,b; cin>>a>>b; add(a,b),add(b,a); } dfs1(1,-1,1); dfs2(1,1); build(1,1,n); cin>>m; while(m--){ int op,u,v,k; cin>>op; if(op==1){ cin>>u>>v>>k; add_path(u,v,k); } else if(op==2){ cin>>u>>k; add_tree(u,k); } else if(op==3){ cin>>u>>v; cout<<query_path(u,v)<<endl; } else{ cin>>u; cout<<query_tree(u)<<endl; } } }