Skip to content
Snippets Groups Projects
Commit 6012144e authored by Bruno Freitas Tissei's avatar Bruno Freitas Tissei
Browse files

Improve HLD

parent 714fcc3e
Branches
No related tags found
No related merge requests found
...@@ -5,11 +5,14 @@ ...@@ -5,11 +5,14 @@
/// - query: O(log^2 n) /// - query: O(log^2 n)
/// - update: O(log n) /// - update: O(log n)
/// Space: O(n log n) /// Space: O(n log n)
///
#define LOG 20 // log2(MAX) /// Caution:
/// - Modifications are necessary if values are associated to vertices;
/// - Modifications are necerrary if other data structure is used.
///
/// Status: Tested (QTREE,URI2887)
ii edge[MAX]; ii edge[MAX];
int par[MAX][LOG];
vector<ii> graph[MAX]; vector<ii> graph[MAX];
template <typename ST> template <typename ST>
...@@ -17,124 +20,85 @@ struct HLD { ...@@ -17,124 +20,85 @@ struct HLD {
ST &seg; ST &seg;
int cnum, ptr; int cnum, ptr;
// Size of subtree, and depth // depth, parent, value of node
vector<int> size, dep; vector<int> dep, par, val;
// Chain's head, chain's index, base array for segtree, // head[i]: head of i-th node's chain;
// position of node in base, and bottommost node // heavy[i]: "special child" of i-th node
vector<int> chead, cidx, base, pos, bot; // pos[i]: position of i-th node on segtree
// bot[i]: bottommost (depth-wise) node on the i-th
// edge (required only when edges have weights)
vector<int> head, heavy, pos, bot;
HLD(int n, ST &seg) : HLD(int n, ST &seg) :
seg(seg), size(n), dep(n, 0), bot(n), seg(seg),
chead(n, -1), cidx(n), base(n), pos(n) dep(n, 0), par(n), val(n),
head(n), heavy(n, -1), pos(n), bot(n)
{ {
mset(par, -1);
cnum = ptr = 0; cnum = ptr = 0;
N = n; // global N for segtree
dfs(0); dfs(0);
decompose(0); decompose(0);
N = ptr; // global N for segtree // (required only when edges have weights)
seg.build(base); for (int i = 0; i < n - 1; ++i)
// bot[i] stores the bottommost (depth-wise) node
// on the i-th edge
for (int i = 0; i < N - 1; ++i)
if (dep[edge[i].fi] > dep[edge[i].se]) if (dep[edge[i].fi] > dep[edge[i].se])
bot[i] = edge[i].fi; bot[i] = edge[i].fi;
else else
bot[i] = edge[i].se; bot[i] = edge[i].se;
} }
void dfs(int x, int p = -1) { int dfs(int x, int p = -1) {
size[x] = 1; int size = 1;
par[x][0] = p; par[x] = p;
for (int i = 1; i < LOG; ++i)
if (par[x][i - 1] != -1)
par[x][i] = par[par[x][i - 1]][i - 1];
int max_size = 0;
for (auto i : graph[x]) for (auto i : graph[x])
if (i.fi != p) { if (i.fi != p) {
dep[i.fi] = dep[x] + 1; dep[i.fi] = dep[x] + 1;
dfs(i.fi, x); val[i.fi] = i.se;
size[x] += size[i.fi]; int isize = dfs(i.fi, x);
}
}
void decompose(int x, int c = -1, int p = -1) { size += isize;
if (chead[cnum] == -1) if (isize > max_size)
chead[cnum] = x; max_size = isize, heavy[x] = i.fi;
pos[x] = ptr;
cidx[x] = cnum;
base[ptr++] = c;
ii sc(-1, -1);
if (graph[x].size() > 1) {
for (auto i : graph[x])
if (i.fi != p)
if (sc.fi == -1 || size[sc.fi] < size[i.fi])
sc = i;
decompose(sc.fi, sc.se, x);
} }
for (auto i : graph[x]) return size;
if (sc.fi != i.fi && i.fi != p) {
cnum++;
decompose(i.fi, i.se, x);
}
} }
int query_up(int a, int b) { void decompose(int x, int h = 0) {
if (a == b) return 0; head[x] = h;
seg.update(ptr, val[x]);
pos[x] = ptr++;
int ca, cb = cidx[b], ans = -1; if (heavy[x] != -1)
while (1) { decompose(heavy[x], h);
ca = cidx[a];
if (ca == cb) {
if (a == b) break;
ans = max(ans, seg.query(pos[b] + 1, pos[a]));
break;
}
ans = max(ans, seg.query(pos[chead[ca]], pos[a]));
a = par[chead[ca]][0];
}
return ans; for (auto i : graph[x])
if (i.fi != par[x] && i.fi != heavy[x])
decompose(i.fi, i.fi);
} }
int lca(int a, int b) { // Queries max edge (or vertice) on the path
int ans = 0; // between a and b
int query(int a, int b) {
if (dep[a] < dep[b]) int ans = seg.ident;
for (; head[a] != head[b]; b = par[head[b]]) {
if (dep[head[a]] > dep[head[b]])
swap(a, b); swap(a, b);
ans = seg.op(ans, seg.query(pos[head[b]], pos[b]));
for (int i = LOG - 1; i >= 0; --i)
if (par[a][i] != -1 && dep[par[a][i]] >= dep[b])
a = par[a][i];
if (a == b)
return a;
for (int i = LOG - 1; i >= 0; --i)
if (par[a][i] != -1 && par[a][i] != par[b][i]) {
a = par[a][i];
b = par[b][i];
} }
return par[a][0]; if (dep[a] > dep[b])
} swap(a, b);
// Queries max edge on the path between a and b // Remove "+ 1" when values are associated with vertices
int query(int a, int b) { return seg.op(ans, seg.query(pos[a] + 1, pos[b]));
int lab = lca(a, b);
return max(query_up(a, lab), query_up(b, lab));
} }
// Updates value of i-th edge // Updates value of i-th edge (or vertice)
void update(int i, int val) { void update(int i, int val) {
seg.update(pos[bot[i]], val); seg.update(pos[bot[i]], val);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment