Kyopro Library
 
読み取り中…
検索中…
一致する文字列を見つけられません
hld.hpp
[詳解]
1#include "../../../kyopro_library/template.hpp"
2
3/// @brief HL分解
4/// @ref 解説:https://hcpc-hokudai.github.io/archive/graph_tree_001.pdf
5struct HLD {
6 HLD(int n) { resize(n); }
7 void add_edge(int a, int b) { g[a].push_back(b),g[b].push_back(a); }
8 void build(int root=0) { dfs1(root),dfs2(root,root); }
9 HLD(const vector<vector<int>>& g, int root=0) {
10 resize(g.size());
11 this->g=g;
12 build(root);
13 }
14
15 /// @brief 頂点 u, v を結ぶパスをHL分解後の辺の列にして返す
16 /**
17 * @brief
18 * `[f, l, r]` として、次を表す。
19 * - `[l, r]`: HL分解後の頂点列
20 * - `f = true` のとき、`[l, r]` はvからuへの向き
21 * - そうでないとき、逆向き
22 */
23 vector<tuple<bool,int,int>> path(int u, int v) {
24 vector<tuple<bool,int,int>> ret;
25 while(head[u]!=head[v]) {
26 if(dep[head[u]]>dep[head[v]]) {
27 ret.push_back({true,pos[head[u]],pos[u]});
28 u=par[head[u]];
29 } else {
30 ret.push_back({false,pos[head[v]],pos[v]});
31 v=par[head[v]];
32 }
33 }
34 if(dep[u]>dep[v]) ret.push_back({true,pos[v],pos[u]});
35 else ret.push_back({false,pos[u],pos[v]});
36 return ret;
37 }
38
39 /// @brief 頂点 u, v のLCAを返す
40 int lca(int u, int v) {
41 while(head[u]!=head[v]) {
42 if(dep[head[u]]>dep[head[v]]) u=par[head[u]];
43 else v=par[head[v]];
44 }
45 return dep[u]<dep[v] ? u:v;
46 }
47
48 /// @brief 頂点vのHL分解後の列での位置を返す
49 int at(int v) { return pos[v]; }
50
51 /// @brief HL分解後の列で、頂点vの部分木に対応する区間を返す
52 pair<int,int> subtree(int v) { return {pos[v],pos2[v]}; }
53
54private:
55 vector<vector<int>> g;
56 vector<int> sz,par,dep,head;
57 vector<int> hld; ///< HLD後の配列
58 vector<int> pos,pos2; ///< hldの逆引き
59 void resize(int n) { g.resize(n),sz.resize(n),par.resize(n),dep.resize(n),pos.resize(n),head.resize(n),pos2.resize(n); }
60 void dfs1(int now, int pre=-1) {
61 par[now]=pre;
62 int res=1;
63 for(int nxt:g[now]) {
64 if(nxt==pre)continue;
65 dep[nxt]=dep[now]+1;
66 dfs1(nxt,now);
67 res+=sz[nxt];
68 }
69 sz[now]=res;
70 }
71 void dfs2(int now, int a, int pre=-1) {
72 pos[now]=hld.size();
73 hld.push_back(now);
74 head[now]=a;
75 if(sz[now]==1) {
76 pos2[now]=hld.size();
77 return;
78 }
79 int mx=0,idx=0;
80 for(int nxt: g[now]) {
81 if(nxt==pre) continue;
82 if(mx<sz[nxt]) {
83 mx=sz[nxt];
84 idx=nxt;
85 }
86 }
87 dfs2(idx,a,now);
88 for(int nxt: g[now]) {
89 if(nxt==pre || nxt==idx) continue;
90 dfs2(nxt,nxt,now);
91 }
92 pos2[now]=hld.size();
93 }
94};
HL分解 解説:https://hcpc-hokudai.github.io/archive/graph_tree_001.pdf
Definition hld.hpp:5
void add_edge(int a, int b)
Definition hld.hpp:7
pair< int, int > subtree(int v)
HL分解後の列で、頂点vの部分木に対応する区間を返す
Definition hld.hpp:52
HLD(int n)
Definition hld.hpp:6
int at(int v)
頂点vのHL分解後の列での位置を返す
Definition hld.hpp:49
void build(int root=0)
Definition hld.hpp:8
HLD(const vector< vector< int > > &g, int root=0)
Definition hld.hpp:9
int lca(int u, int v)
頂点 u, v のLCAを返す
Definition hld.hpp:40
vector< tuple< bool, int, int > > path(int u, int v)
頂点 u, v を結ぶパスをHL分解後の辺の列にして返す
Definition hld.hpp:23