1 /**
2 Unstable
3 */
4 module dkh.graph.hldecomp;
5 
6 import dkh.container.stackpayload;
7 
8 struct HLInfo {
9     int[2][] id; //vertex -> [line id, line pos]
10     int[][] lines; //line id -> line list(top to bottom)
11     int[2][] par; //line id -> [parent line id, parent line pos]
12     int[] lineDPS; //line id -> line depth
13     this(size_t n) {
14         id = new int[2][n];
15     }
16 }
17 
18 /// calc lca(a, b)
19 int calcLCA(in HLInfo hl, int a, int b) {
20     import std.algorithm : swap;
21     with (hl) {
22         int[2] xl = id[a];
23         int[2] yl = id[b];
24         if (lineDPS[xl[0]] < lineDPS[yl[0]]) swap(xl, yl);
25         while (lineDPS[xl[0]] > lineDPS[yl[0]]) {
26             xl = par[xl[0]];
27         }
28         while (xl[0] != yl[0]) {
29             xl = par[xl[0]];
30             yl = par[yl[0]];
31         }
32         if (xl[1] > yl[1]) swap(xl, yl);
33         return lines[xl[0]][xl[1]];
34     }
35 }
36 
37 HLInfo hlDecomposition(T)(in T g, int rt) {
38     auto n = g.length;
39     auto hl = HLInfo(n);
40     with (hl) {
41         int[] sz = new int[n];
42         int calcSZ(int p, int b) {
43             sz[p] = 1;
44             foreach (e; g[p]) {
45                 if (e.to == b) continue;
46                 sz[p] += calcSZ(e.to, p);
47             }
48             return sz[p];
49         }
50         calcSZ(rt, -1);
51         int idc = 0;
52         StackPayload!(int[2]) par_buf;
53         StackPayload!int line_buf, dps_buf;
54         void dfs(int p, int b, int height) {
55             line_buf ~= p;
56             id[p] = [idc, height];
57             int nx = -1, buf = -1;
58             foreach (e; g[p]) {
59                 if (e.to == b) continue;
60                 if (buf < sz[e.to]) {
61                     buf = sz[e.to];
62                     nx = e.to;
63                 }
64             }
65             if (nx == -1) {
66                 //make line
67                 lines ~= line_buf.data.dup;
68                 line_buf.clear;
69                 idc++;
70                 return;
71             }
72 
73             dfs(nx, p, height+1);
74             foreach (e; g[p]) {
75                 if (e.to == b || e.to == nx) continue;
76                 par_buf ~= id[p];
77                 dps_buf ~= dps_buf.data[id[p][0]] + 1;
78                 dfs(e.to, p, 0);
79             }
80         }
81         par_buf ~= [-1, -1];
82         dps_buf ~= 0;
83         dfs(rt, -1, 0);
84         par = par_buf.data;
85         lineDPS = dps_buf.data;
86     }
87     return hl;
88 }