Heavy-light-декомпозиция: различия между версиями
Перейти к навигации
Перейти к поиску
Ctrlalt (обсуждение | вклад) (Новая страница: « #include <stdio.h> #include <vector> #include <queue> #include <set> #include <map> #include <algorithm> #include <iostream> using namespace std; class …») |
Ctrlalt (обсуждение | вклад) Нет описания правки |
||
| Строка 1: | Строка 1: | ||
struct SegmentTree { | |||
int size; | |||
vector<int> t; | |||
int | |||
int query(int v, int vl, int vr, int l, int r) { | int query(int v, int vl, int vr, int l, int r) { | ||
if ( | if (vr < l || r < vl) | ||
return - | return -1e9; | ||
if (l <= vl && vr <= r) | if (l <= vl && vr <= r) | ||
return t[v]; | return t[v]; | ||
| Строка 30: | Строка 13: | ||
return max(ql, qr); | return max(ql, qr); | ||
} | } | ||
void modify(int v, int vl, int vr, int | |||
if ( | void modify(int v, int vl, int vr, int index, int value) { | ||
if (vr < index || index < vl) | |||
return; | return; | ||
if ( | if (vl == vr) { | ||
t[v] += | t[v] += value; | ||
return; | return; | ||
} | } | ||
int vm = vl + (vr - vl) / 2; | int vm = vl + (vr - vl) / 2; | ||
modify(2 * v + 1, vl, vm, | modify(2 * v + 1, vl, vm, index, value); | ||
modify(2 * v + 2, vm + 1, vr, | modify(2 * v + 2, vm + 1, vr, index, value); | ||
t[v] = max(t[2 * v + 1], t[2 * v + 2]); | t[v] = max(t[2 * v + 1], t[2 * v + 2]); | ||
} | } | ||
SegmentTree(int size) : size(size), t(4 * size) {} | |||
int getMax(int l, int r) { | |||
int | |||
return query(0, 0, size - 1, l, r); | return query(0, 0, size - 1, l, r); | ||
} | } | ||
void | |||
modify(0, 0, size - 1, | void addValue(int index, int value) { | ||
modify(0, 0, size - 1, index, value); | |||
} | } | ||
} | }; | ||
int | struct HeavyLightDecomposition { | ||
vector<vector<int>> graph; | |||
vector<int> l, r, parent, subtreeSize; | |||
int | int timer = 0; | ||
vector<vector<int>> paths; | |||
vector<int> pathOf, posOf; | |||
vector<SegmentTree> segmentTrees; | |||
HeavyLightDecomposition(int vertexCount) : | |||
graph(vertexCount), l(vertexCount), r(vertexCount), | |||
parent(vertexCount), subtreeSize(vertexCount), | |||
pathOf(vertexCount), posOf(vertexCount) {} | |||
void addEdge(int a, int b) { | |||
graph[a].push_back(b); | |||
graph[b].push_back(a); | |||
} | } | ||
int dfs(int v, int p) { | |||
l[v] = timer++; | |||
parent[v] = p; | |||
subtreeSize[v] = 1; | |||
for (int to : graph[v]) | |||
if (to != p) | |||
subtreeSize[v] += dfs(to, v); | |||
r[v] = timer++; | |||
return subtreeSize[v]; | |||
} | } | ||
bool isAncestor(int a, int b) { | |||
return l[a] <= l[b] && r[b] <= r[a]; | |||
} | } | ||
void buildPath(int v, int pathIndex) { | |||
if (paths.size() == pathIndex) | |||
paths.emplace_back(); | |||
paths[pathIndex].push_back(v); | |||
pathOf[v] = pathIndex; | |||
posOf[v] = paths[pathIndex].size() - 1; | |||
int maxTo = -1; | |||
for (int to : graph[v]) | |||
if (to != parent[v] && (maxTo == -1 || subtreeSize[maxTo] < subtreeSize[to])) | |||
maxTo = to; | |||
for (int to : graph[v]) { | |||
if (to == parent[v]) | |||
continue; | |||
if (to == maxTo) | |||
buildPath(to, pathIndex); | |||
else | |||
buildPath(to, paths.size()); | |||
} | |||
} | } | ||
void prepare(int root) { | |||
dfs(root, -1); | |||
buildPath(root, 0); | |||
for (vector<int> &path : paths) | |||
segmentTrees.push_back(SegmentTree(path.size())); | |||
} | } | ||
int getMax(int a, int b) { | |||
int res = 0; | |||
for (; !isAncestor(paths[pathOf[a]][0], b); a = parent[paths[pathOf[a]][0]]) | |||
res = max(res, segmentTrees[pathOf[a]].getMax(0, posOf[a])); | |||
for (; !isAncestor(paths[pathOf[b]][0], a); b = parent[paths[pathOf[b]][0]]) | |||
res = max(res, segmentTrees[pathOf[b]].getMax(0, posOf[b])); | |||
if (posOf[a] > posOf[b]) | |||
swap(a, b); | |||
return max(res, segmentTrees[pathOf[a]].getMax(posOf[a], posOf[b])); | |||
} | } | ||
void addValue(int v, int value) { | |||
segmentTrees[pathOf[v]].addValue(posOf[v], value); | |||
} | } | ||
} | }; | ||
== Ссылки на задачи == | == Ссылки на задачи == | ||
Версия от 21:58, 14 февраля 2026
struct SegmentTree {
int size;
vector<int> t;
int query(int v, int vl, int vr, int l, int r) {
if (vr < l || r < vl)
return -1e9;
if (l <= vl && vr <= r)
return t[v];
int vm = vl + (vr - vl) / 2;
int ql = query(2 * v + 1, vl, vm, l, r);
int qr = query(2 * v + 2, vm + 1, vr, l, r);
return max(ql, qr);
}
void modify(int v, int vl, int vr, int index, int value) {
if (vr < index || index < vl)
return;
if (vl == vr) {
t[v] += value;
return;
}
int vm = vl + (vr - vl) / 2;
modify(2 * v + 1, vl, vm, index, value);
modify(2 * v + 2, vm + 1, vr, index, value);
t[v] = max(t[2 * v + 1], t[2 * v + 2]);
}
SegmentTree(int size) : size(size), t(4 * size) {}
int getMax(int l, int r) {
return query(0, 0, size - 1, l, r);
}
void addValue(int index, int value) {
modify(0, 0, size - 1, index, value);
}
};
struct HeavyLightDecomposition {
vector<vector<int>> graph;
vector<int> l, r, parent, subtreeSize;
int timer = 0;
vector<vector<int>> paths;
vector<int> pathOf, posOf;
vector<SegmentTree> segmentTrees;
HeavyLightDecomposition(int vertexCount) :
graph(vertexCount), l(vertexCount), r(vertexCount),
parent(vertexCount), subtreeSize(vertexCount),
pathOf(vertexCount), posOf(vertexCount) {}
void addEdge(int a, int b) {
graph[a].push_back(b);
graph[b].push_back(a);
}
int dfs(int v, int p) {
l[v] = timer++;
parent[v] = p;
subtreeSize[v] = 1;
for (int to : graph[v])
if (to != p)
subtreeSize[v] += dfs(to, v);
r[v] = timer++;
return subtreeSize[v];
}
bool isAncestor(int a, int b) {
return l[a] <= l[b] && r[b] <= r[a];
}
void buildPath(int v, int pathIndex) {
if (paths.size() == pathIndex)
paths.emplace_back();
paths[pathIndex].push_back(v);
pathOf[v] = pathIndex;
posOf[v] = paths[pathIndex].size() - 1;
int maxTo = -1;
for (int to : graph[v])
if (to != parent[v] && (maxTo == -1 || subtreeSize[maxTo] < subtreeSize[to]))
maxTo = to;
for (int to : graph[v]) {
if (to == parent[v])
continue;
if (to == maxTo)
buildPath(to, pathIndex);
else
buildPath(to, paths.size());
}
}
void prepare(int root) {
dfs(root, -1);
buildPath(root, 0);
for (vector<int> &path : paths)
segmentTrees.push_back(SegmentTree(path.size()));
}
int getMax(int a, int b) {
int res = 0;
for (; !isAncestor(paths[pathOf[a]][0], b); a = parent[paths[pathOf[a]][0]])
res = max(res, segmentTrees[pathOf[a]].getMax(0, posOf[a]));
for (; !isAncestor(paths[pathOf[b]][0], a); b = parent[paths[pathOf[b]][0]])
res = max(res, segmentTrees[pathOf[b]].getMax(0, posOf[b]));
if (posOf[a] > posOf[b])
swap(a, b);
return max(res, segmentTrees[pathOf[a]].getMax(posOf[a], posOf[b]));
}
void addValue(int v, int value) {
segmentTrees[pathOf[v]].addValue(posOf[v], value);
}
};
Ссылки на задачи
Ссылки
- e-maxx.ru — Heavy-light декомпозиция
- blog.anudeep2011.com — Heavy Light Decomposition
- CodeLibrary — Heavy-light tree decomposition for edges or vertices
- Algos — Heavy-light decomposition with segment trees in paths
- Algos — Finding LCA (Least common ancestor) of two vertices in the tree. Uses heavy-light decomposition