LIB::HeavyLightDecomposition
heavy edge と light edge に分解してセグメント木などのデータ構造と併用することでパスクエリを高速に処理する 構築 部分木クエリ パスクエリ
https://qiita.com/Pro_ktmr/items/4e1e051ea0561772afa3
https://hcpc-hokudai.github.io/archive/graph_tree_001.pdf
https://tubo28.me/compprog/algorithm/hld/
メンバ関数
HeavyLightDecomposition(graph &ag, ll ar)
分解する木agと分解するときの根ノードarを入力
pll path_idx(ll nd)
ノード nd が含まれるようなパス閉区間を index で返す
メンバ変数
parent[nd]
ノード nd の親(根のときは -1 を返す)
subsize[nd]
ノード nd を根とする部分木のノード数
depth[nd]
ノード nd の根ノードからの距離
head[nd]
ノード nd が属するパスにおける先頭ノード
tail[nd]
ノード nd が属するパスにおける末尾ノード
prev[nd]
ノード nd の前ノード(パスの範囲を超えるとき -1 を返す)
next[nd]
ノード nd の次ノード(パスの範囲を超えるとき -1 を返す)
all_path
分解した全てのパス集合( head の深さ昇順に入っている)
#include <bits/stdc++.h> using namespace std; namespace LIB { class HeavyLightDecomposition { using ll = long long; using graph=vector<vector<ll>>; using vpll=vector<pair<ll,ll>>; ll n; std::vector<ll> at; void run(const ll root) { static ll stk[1000001]; ll k=0; stk[k++]=root; parent[root]=-1; depth[root]=0; while(k) { ll v=stk[--k]; if(v>=0) { stk[k++]=~v; for(auto &to:g[v]) { ll ch=to; if(depth[ch]==-1) { depth[ch]=depth[v]+1; parent[ch]=v; stk[k++]=ch; } } } else { ll m=0; v=~v; subsize[v]=1; for(auto &to:g[v]) { ll ch=to; if(parent[v]==ch) continue; subsize[v]+=subsize[ch]; if(m<subsize[ch]) m=subsize[ch],next[v]=ch; } } } k = 0; stk[k++] = root; while(k) { ll h=stk[--k]; for(auto &to:g[h]) if(parent[h]!=to) stk[k++]=to; if (path[h]!=-1) continue; all_path.push_back(std::vector<ll>()); std::vector<ll> &pt=all_path.back(); for(ll cur=h;cur!=-1;) pt.push_back(cur),cur=next[cur]; for(ll i=0;i<(ll)pt.size();i++) { ll v=pt[i]; head[v]=pt.front(); tail[v]=pt.back(); next[v]=i+1 != (ll)pt.size()?pt[i+1]:-1; prev[v]=i!=0?pt[i-1]:-1; path[v]=all_path.size()-1; at[v]=i; } } ll i=0; for(auto& ch:all_path) for(auto& e:ch) idx[e]=i++; } public: graph g; std::vector<std::vector<ll>> all_path; std::vector<ll> depth,head,idx,next,parent,path,prev,subsize,tail; HeavyLightDecomposition(graph &ag, ll ar): n(ag.size()),at(n,0),g(ag),all_path(0), depth(n,-1),head(n,0),idx(n,0),next(n,-1),parent(n,0),path(n,-1),prev(n,-1),subsize(n,0),tail(n,0) { run(ar); } vpll all_path_idx(ll an, ll bn) { vpll res; while(head[an]!=head[bn]) { if(depth[head[an]]<=depth[head[bn]]) res.push_back({idx[head[bn]],idx[bn]}),bn=parent[head[bn]]; else res.push_back({idx[head[an]],idx[an]}),an=parent[head[an]]; } res.push_back({idx[an],idx[bn]}); for(auto& e:res) if(e.first>e.second) swap(e.first,e.second); return res; } ll lca(ll u, ll v) { while(path[u]!=path[v]) { if(depth[head[u]]>depth[head[v]]) u=parent[head[u]]; else v=parent[head[v]]; } return depth[u]<depth[v]?u:v; } pll path_idx(ll nd) { return {idx[head[nd]],idx[tail[nd]]}; } }; }