Wrote out Centroid, Added to Custom_Cpp_STL
also added problem to func_graphs but it will probably be taken out as I am still unable to solve it even after being told solution
This commit is contained in:
parent
f2a6ac2409
commit
8851ff6a59
3 changed files with 115 additions and 16 deletions
|
@ -5,7 +5,7 @@ author: Siyong Huang, Benjamin Qi
|
|||
prerequisites:
|
||||
- sorting-custom
|
||||
- intro-ordered
|
||||
description: "?"
|
||||
description: "More ways to write custom comparators in C++ and incorporating them into STL objects."
|
||||
frequency: 1
|
||||
---
|
||||
|
||||
|
@ -43,7 +43,6 @@ int main() {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
## Comparator
|
||||
|
||||
```cpp
|
||||
|
@ -67,10 +66,20 @@ int main() {
|
|||
}
|
||||
```
|
||||
|
||||
<Info title="Pro Tip" >
|
||||
|
||||
You can also use the following syntax to declare set `v` using a function
|
||||
|
||||
`set<Edge,decltype(*cmp)> v(cmp);`
|
||||
|
||||
</Info>
|
||||
|
||||
Lambda expressions also work:
|
||||
|
||||
```cpp
|
||||
auto cmp = [](const Edge& x, const Edge& y) { return x.w < y.w; };
|
||||
//The real type of cmp is function<bool(const Edge&, const Edge&)>
|
||||
//auto is used for short
|
||||
|
||||
int main() {
|
||||
int M = 4;
|
||||
|
@ -83,7 +92,13 @@ int main() {
|
|||
}
|
||||
```
|
||||
|
||||
In this case, we can shorten the declaration of `v` by writing `set<Edge,decltype(cmp)> v(cmp);` instead.
|
||||
<Info title="Pro Tip" >
|
||||
|
||||
You can also use the following syntax to declare set `v` using a lambda
|
||||
|
||||
`set<Edge,decltype(cmp)> v(cmp);`
|
||||
|
||||
</Info>
|
||||
|
||||
## Functors
|
||||
|
||||
|
@ -127,9 +142,17 @@ int main() {
|
|||
}
|
||||
```
|
||||
|
||||
<Info title="Pro Tip">
|
||||
|
||||
One functor can be used for multiple objects. Just keep overloading the `()` operator!
|
||||
|
||||
</Info>
|
||||
|
||||
## Built-In Functors
|
||||
|
||||
Overloading the less than operator (`<`) automatically generates the functor `less<Edge>`. Similarly, overloading `>` automatically generates the functor [`greater<Edge>`](https://en.cppreference.com/w/cpp/utility/functional/greater). We can use this to store a set in reverse order.
|
||||
Overloading the less than operator (`<`) automatically generates the functor [`less<Edge>`](https://en.cppreference.com/w/cpp/utility/functional/less).
|
||||
Similarly, overloading (`>`) automatically generates the functor [`greater<Edge>`](https://en.cppreference.com/w/cpp/utility/functional/greater).
|
||||
We can use this to store a set in reverse order.
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
|
@ -167,3 +190,16 @@ set<int,greater<int>> a;
|
|||
map<int,string,greater<int>> b;
|
||||
priority_queue<int,vector<int>,greater<int>> c;
|
||||
```
|
||||
|
||||
<Warning title="Priority Queues">
|
||||
|
||||
In C++, priority queues are sorted in decreasing order.
|
||||
Specifically, larger elements have higher 'priority' and are popped first.
|
||||
|
||||
If you want smaller elements to be at the front of the queue, two ways are listed below
|
||||
|
||||
1. Overload the (`<`) operator to output the opposite effect.
|
||||
|
||||
2. Overload the (`>`) operator properly and use the (`greater<T>`) functor.
|
||||
|
||||
</Warning>
|
||||
|
|
|
@ -24,23 +24,29 @@ export const metadata = {
|
|||
new Problem("POI", "Mafia", "https://szkopul.edu.pl/problemset/problem/w3YAoAT3ej27YeiaNWjK57_G/site/?key=statement", "Hard", false, ["Func Graph"], ""),
|
||||
new Problem("POI", "Spies", "https://szkopul.edu.pl/problemset/problem/r6tMTfvQFPAEfQioYMCQndQe/site/?key=statement", "Hard", false, [], ""),
|
||||
new Problem("POI", "Frog", "https://szkopul.edu.pl/problemset/problem/qDH9CkBHZKHY4vbKRBlXPrA7/site/?key=statement", "Hard", false, [], ""),
|
||||
new Problem("ojuz", "Space Pirate", "JOI14_space_pirate", "Very Hard", false, ["Graphs"], "One of the most difficult problems of all time. Build a tree with a single back edge. Break into three cases: path -> other cycle, path -> subtree, path -> non-subtree. Then perform some black magic."),
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
## Functional Graphs
|
||||
|
||||
We'll consider graphs like the one presented in this problem:
|
||||
|
||||
<Problems problems={metadata.problems.sample} />
|
||||
|
||||
< br/>
|
||||
|
||||
Aka **successor graph**.
|
||||
In a **functional graph**, each node has exactly one out-edge.
|
||||
This is also commonly referred to as a **successor graph**.
|
||||
|
||||
### Resources
|
||||
|
||||
<Resources>
|
||||
<Resource source="CPH" title="16.3, 16.4 - Successor Graphs"></Resource>
|
||||
</Resources>
|
||||
|
||||
## Implementation
|
||||
### Implementation
|
||||
|
||||
The following sample code counts the number of cycles in such a graph. The "stack" contains nodes that can reach the current node. If the current node points to a node `v` on the stack (`on_stack[v]` is true), then we know that a cycle has been created. However, if the current node points to a node `v` that has been previously visited but is not on the stack, then we know that the current chain of nodes points into a cycle that has already been considered.
|
||||
|
||||
|
@ -82,6 +88,14 @@ int main()
|
|||
|
||||
**Floyd's Algorithm**, also commonly referred to as the **Tortoise and Hare Algorithm**, is capable of detecting cycles in a functional graph in $O(N)$ time and $O(1)$ memory (not counting the graph itself)
|
||||
|
||||
### Resources
|
||||
|
||||
<Resources>
|
||||
<Resource source="Medium" title="The Tortoise and the Hare (Floyd's Algorithm)" url="https://medium.com/@tuvo1106/the-tortoise-and-the-hare-floyds-algorithm-87badf5f7d41"></Resource>
|
||||
</Resources>
|
||||
|
||||
### Implementation
|
||||
|
||||
```cpp
|
||||
//UNTESTED
|
||||
pair<int, int> detect_cycle(int *next, int start_node) //return pair(length of cycle, distance from start node to in cycle)
|
||||
|
@ -105,12 +119,7 @@ pair<int, int> detect_cycle(int *next, int start_node) //return pair(length of c
|
|||
}
|
||||
```
|
||||
|
||||
<Resources>
|
||||
<Resource source="Medium" title="The Tortoise and the Hare (Floyd's Algorithm)" url="https://medium.com/@tuvo1106/the-tortoise-and-the-hare-floyds-algorithm-87badf5f7d41"></Resource>
|
||||
</Resources>
|
||||
|
||||
<IncompleteSection />
|
||||
|
||||
## Problems
|
||||
### Problems
|
||||
|
||||
<Problems problems={metadata.problems.general} />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
id: centroid
|
||||
title: "Centroid Decomposition"
|
||||
author: Benjamin Qi
|
||||
author: Benjamin Qi, Siyong Huang
|
||||
prerequisites:
|
||||
- dfs
|
||||
- SRQ
|
||||
|
@ -14,12 +14,12 @@ import { Problem } from "../models";
|
|||
export const metadata = {
|
||||
problems: {
|
||||
general: [
|
||||
new Problem("CF", "Ciel the Commander", "problemset/problem/321/C", "Easy", false, ["Centroid"]),
|
||||
new Problem("CF", "Ciel the Commander", "problemset/problem/321/C", "Easy", false, ["Centroid"], ""),
|
||||
new Problem("CF", "Sherlock's bet to Moriarty", "contest/776/problem/F", "Normal", false, ["Centroid"], ""),
|
||||
new Problem("CF", "Digit Tree", "contest/715/problem/C", "Normal", false, ["Centroid", "NT"], ""),
|
||||
new Problem("CF", "Double Tree", "contest/1140/problem/G", "Normal", false, ["Centroid", "DP"], ""),
|
||||
new Problem("ojuz", "JOI - Factories", "JOI14_factories", "Normal", false, ["Centroid"], ""),
|
||||
new Problem("CF", "Sum of Prefix Sums", contest/1303/problem/G", "Hard", false, ["Centroid", "CHT"], ""),
|
||||
new Problem("CF", "Sum of Prefix Sums", "contest/1303/problem/G", "Hard", false, ["Centroid", "CHT"], ""),
|
||||
new Problem("YS", "Frequency Table of Tree Distance", "frequency_table_of_tree_distance", "Hard", false, ["Centroid", "FFT"], ""),
|
||||
new Problem("DMOJ", "Bob Equilibrium", "dmopc19c7p6", "Hard", false, ["Centroid"], "tight time limit"),
|
||||
new Problem("DMOJ", "Time Traveller Imaxblue", "tc19summerh", "Hard", false, ["Centroid"], ""),
|
||||
|
@ -29,6 +29,12 @@ export const metadata = {
|
|||
}
|
||||
};
|
||||
|
||||
## Centroid Decomposition
|
||||
|
||||
**Centroid Decomposition** is a divide and conquer technique for trees.
|
||||
The **centroid** of a tree is a node which, if rooted, results in no other nodes having a subtree of size greater than $\frac{N}{2}$.
|
||||
**Centroid Decomposition** works by repeated splitting the tree and each of the resulting subgraphs at the centroid, producing $O(\log N)$ layers of subgraphs.
|
||||
|
||||
### Tutorial
|
||||
|
||||
<Resources>
|
||||
|
@ -36,6 +42,54 @@ export const metadata = {
|
|||
<Resource source="GFG" title="Centroid Decomposition of Tree" url="centroid-decomposition-of-tree"></Resource>
|
||||
</Resources>
|
||||
|
||||
### Implementation
|
||||
|
||||
<LanguageSection>
|
||||
|
||||
<CPPSection>
|
||||
|
||||
<!-- pulled from https://codeforces.com/contest/1303/submission/76216413, which I think is my most recent centroid problem -->
|
||||
|
||||
```cpp
|
||||
bool r[MN];//removed
|
||||
int s[MN];//subtree size
|
||||
int dfs(int n, int p = 0)
|
||||
{
|
||||
s[n] = 1;
|
||||
for(int x : a[n])
|
||||
if(x != p && !r[x])
|
||||
s[n] += dfs(x, n);
|
||||
return s[n];
|
||||
}
|
||||
int get_centroid(int n, int ms, int p = 0)//n = node, ms = size of tree, p = parent
|
||||
{
|
||||
for(int x : a[n])
|
||||
if(x != p && !r[x])
|
||||
if(s[x]*2 > ms)
|
||||
return get_centroid(x, ms, n);
|
||||
return n;
|
||||
}
|
||||
void centroid(int n = 1)
|
||||
{
|
||||
int C = get_centroid(n, dfs(n));
|
||||
|
||||
//do something
|
||||
|
||||
r[C] = 1;
|
||||
for(int x : a[C])
|
||||
if(!r[x])
|
||||
centroid(x);
|
||||
}
|
||||
```
|
||||
|
||||
</CPPSection>
|
||||
|
||||
<JavaSection />
|
||||
|
||||
<PySection />
|
||||
|
||||
</LanguageSection>
|
||||
|
||||
### Problems
|
||||
|
||||
<Problems problems={metadata.problems.general} />
|
||||
|
|
Reference in a new issue