Dsu with lazy propagation
Разница между ru3 и ru4, 1774 символ(ов) изменены
A trick forТрюк для DSU (disjoint set union) that I recently came across:↵
↵
We have elements on which we need to perform two types of queries:↵
↵
1. Union — merge the sets containing elements
, с которым я недавно столкнулся:↵
↵
У нас есть элементы, над которыми нужно выполнять два типа запросов:↵
↵
1. Union — объединить множества, содержащие элементы
 v1 andи v2.↵
2. Add — 
for all i in the set containing element v, add some valueдля всех i в множестве, содержащем элемент v, прибавить некоторое значение x toк a[i].↵
↵
To support this efficiently, we can store implicit modifications in the nodes, similar to lazy propagation in a segment tree, but without explicitly pushing updates down.↵
↵
For an add query, we find the root of the tree containing vertex v and add the modification to that root.↵
When we need to get the actual value of a[i], we first compress the path to the root and apply the root’s modification. During path compression (in the recursive process of reattaching the nodes), we also apply the parent’s modification to the current node.↵
↵
For the union operation, we can either:↵
↵
1. create a new virtual node to act as the parent of both components
Чтобы поддерживать это эффективно, можно хранить неявные модификации в вершинах — аналогично ленивым обновлениям (lazy propagation) в дереве отрезков, но без явной передачи изменений вниз.↵
↵
При запросе Add мы находим корень дерева, содержащего вершину v, и добавляем модификацию в этот корень.↵
Когда нужно получить реальное значение a[i], мы сначала выполняем сжатие пути к корню и применяем модификации от корня.↵
Во время сжатия пути (в процессе рекурсивного переподключения вершин) мы также применяем модификацию родителя к текущей вершине.↵
↵
Для операции Union можно действовать двумя способами:↵
↵
1. Создать новую виртуальную вершину, которая станет родителем обоих компонентов
.↵
21. attach one root under the other and apply the inverse modification to the subtree that now becomes a child.↵
↵
The second approach is a bit trickier to implement when the modifications are more complex.↵
↵
code:
Прикрепить один корень к другому и применить обратную модификацию к поддереву, которое становится потомком.↵
↵
Второй способ немного сложнее в реализации, особенно если модификации более сложные.
↵
↵
<spoiler summary="Spoiler">↵
~~~~~↵
void apply(int v, long long add) {↵
    res[v] += add;↵
    lazyAdd[v] += add;↵
}↵
↵
int getPar(int v) {↵
    if (v == comp[v]) return v;↵
    int p = getPar(comp[v]);↵
    if (comp[v] != p) apply(v, lazyAdd[comp[v]]);↵
    return comp[v] = p;↵
}↵
↵
long long getVal(int v) {↵
    int p = getPar(v);↵
    if (v == p) return res[v];↵
    return res[v] + lazyAdd[p];↵
}↵
↵
void add(int v, long long x) {↵
    v = getPar(v);↵
    apply(v, x);↵
}↵
↵
void unionSet(int v1, int v2) {↵
    v1 = getPar(v1);↵
    v2 = getPar(v2);↵
    if (v1 == v2) return;↵
↵
    int p = ++allNodes;↵
    comp[v1] = p;↵
    comp[v2] = p;↵
↵
    res[p] = 0;↵
    lazyAdd[p] = 0;↵
    sz[p] = sz[v1] + sz[v2] + 1;↵
}↵
~~~~~↵
</spoiler>↵
↵
↵

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
ru4 Русский pcheloveks 2025-11-09 23:58:14 1774 (опубликовано)
en2 Английский pcheloveks 2025-11-09 23:27:42 0 (published)
en1 Английский pcheloveks 2025-11-09 23:24:52 1928 Initial revision for English translation (saved to drafts)
ru3 Русский pcheloveks 2025-11-09 23:17:35 40
ru2 Русский pcheloveks 2025-11-09 23:16:17 4
ru1 Русский pcheloveks 2025-11-09 23:10:50 1883 Первая редакция (сохранено в черновиках)