[模板] 樹鏈剖分(輕重鏈剖分)
阿新 • • 發佈:2021-08-12
一些定義
- 重兒子:
結點所有兒子裡子樹規模最大的結點,即\(sz[ x ]\) 最大。
我第一次接觸這個概念居然不是在這,而是在這。
有時間再寫題解吧,這是一個不錯的思維題。
- 重鏈:
從重兒子一直延伸到葉子結點的路徑。
- 樹鏈:
任意兩點間的距離 ( 不嚴謹的說。
原理:
通過有序的 dfs
先跑重兒子,回來再跑輕兒子,最後形成一個特殊的 dfs 序。
兩遍 dfs
\(1.\) 處理出需要的資訊:
\(de , fa , sz , top\)(所處於重鏈的起點編號)。
\(2.\) 跑特殊的 \(dfs\) ,形成 \(dfs\) 序。
\(dfs\) 序的性質
-
一條鏈上的序是連續的。
-
一棵子樹內的 dfs 序為 \(dfn[x]\) 到 \(dfn[x] + sz[x] + 1\),也是連續的。
樹鏈剖分要解決的問題
給一棵子樹或者一條樹鏈上的結點全部加上一個權值。
樹鏈剖分的主演算法
利用特殊 dfs 序的性質,分幾步來看:
假設現在要將樹鏈 \((x , y)\)上的權值加上某個數。
\(1.\) 如果 \(x\) 和 \(y\) 所處鏈不同,選取深度較大的結點爬到鏈端處,一邊跑一邊把路徑上的結點加上權值 (感性理解)。
\(2.\) 最後肯定有一個結點跑到 \(x\) 和 \(y\) 的 \(lca\) 處。
\(3.\)
inline int qRange(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); res=0; query(1,1,n,id[top[x]],id[x]); ans+=res; ans%=mod; x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); res=0; query(1,1,n,id[x],id[y]); ans+=res; return ans%mod; }
最後用線段樹維護區間和即可。