This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
usaco-guide/content/6_Plat/Merging.mdx
2020-06-27 22:11:09 -04:00

120 lines
4.1 KiB
Text

---
id: merging
title: "Small-To-Large Merging"
author: Michael Cao
prerequisites:
- Silver - Depth First Search
- Gold - Point Update Range Sum
description: "?"
frequency: 1
---
import { Problem } from "../models";
export const metadata = {
problems: {
sam: [
new Problem("CSES", "Distinct Colors", "1139", "Intro", false, ["Merging"]),
],
general: [
new Problem("CF", "Lomsat gelral", "contest/600/problem/E", "Normal", false, ["Merging"]),
new Problem("Plat", "Promotion Counting", "696", "Normal", false, ["Merging", "Indexed Set"], ""),
new Problem("Gold", "Favorite Colors", "1042", "Hard", false, ["DSU"], "Small to large merging is mentioned in the editorial, but we were unable to break solutions that just merged naively."),
new Problem("Plat", "Disruption", "842", "Hard", false, ["Merging"]),
]
}
};
## Additional Reading
<resources>
<resource source="CPH" title="18.4 - Merging Data Structures"></resource>
<resource source="CF" title="Arpa - Sack (DSU on Tree)" url="blog/entry/44351"></resource>
<resource source="CF" title="tuwuna - Explaining DSU on Trees" url="blog/entry/67696"></resource>
</resources>
## Merging Sets
<problems-list problems={metadata.problems.sam} />
Let's consider a tree rooted at node $1$, where each node has a color.
For each node, let's store a set containing only that node, and we want to merge the sets in the nodes subtree together such that each node has a set consisting of all colors in the nodes subtree. Doing this allows us to solve a variety of problems, such as query the number of distinct colors in each subtree. Doing this naively, however, yields a runtime complexity of $O(N^2)$.
However, with just a few lines of code, we can significantly speed this up. Note that [swap](http://www.cplusplus.com/reference/utility/swap/) exchanges two sets in $O(1)$ time.
```cpp
if(a.size() < b.size()){ //for two sets a and b
swap(a,b);
}
```
By merging the smaller set into the larger one, the runtime complexity becomes $O(N\log N).$ ?? (Ben - this is false)
### Proof
When merging two sets, you move from the smaller set to the larger set. If the size of the smaller set is $X$, then the size of the resulting set is at least $2X$. Thus, an element that has been moved $Y$ times will be in a set of size $2^Y$, and since the maximum size of a set is $N$ (the root), each element will be moved at most $O(\log N$) times leading to a total complexity of $O(N\log N)$.
<spoiler title="Full Code">
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MX = 200005;
vector<int> adj[MX]; set<int> col[MX]; long long ans[MX];
void dfs(int v, int p){
for(int e : adj[v]){
if(e != p){
dfs(e, v);
if(col[v].size() < col[e].size()){
swap(col[v], col[e]);
}
for(int a : col[e]){
col[v].insert(a);
}
col[e].clear();
}
}
ans[v] = col[v].size();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n; cin >> n;
for(int i = 0; i < n; i++){
int x; cin >> x;
col[i].insert(x);
}
for(int i = 0; i < n - 1; i++){
int u,v; cin >> u >> v;
u--; v--;
adj[u].push_back(v); adj[v].push_back(u);
}
dfs(0,-1);
for(int i = 0; i < n; i++){
cout << ans[i] << " ";
}
}
```
</spoiler>
## Generalizing
A set doesn't have to be an `std::set`. Many data structures can be merged, such as `std::map` or `std:unordered_map`. However, `std::swap` doesn't necessarily work in $O(1)$ time; for example, swapping two [arrays](http://www.cplusplus.com/reference/array/array/swap/) takes time linear in the sum of the sizes of the arrays, and the same goes for indexed sets. For two indexed sets `a` and `b` we can use `a.swap(b)` in place of `swap(a,b)` (documentation?).
<info-block title="Challenge">
Prove that if you instead merge sets that have size equal to the depths of the subtrees, then small to large merging does $O(N)$ insert calls.
(be specific about what this means?)
</info-block>
## Problems
<problems-list problems={metadata.problems.general} />