resolve merge

This commit is contained in:
Nathan Wang 2020-06-27 12:38:29 -07:00
commit c03a41c966
29 changed files with 435 additions and 239 deletions

View file

@ -25,6 +25,7 @@ export const metadata = {
new Problem("CSES", "Tree Distances II", "1133", "Normal", false, ["Tree", "DFS"]),
new Problem("CF", "Wizard's Tour", "contest/860/problem/D", "Normal", false, ["Tree", "DFS"]),
new Problem("POI", "Hotels", "https://szkopul.edu.pl/problemset/problem/gDw3iFkeVm7ZA3j_16-XR7jI/site/?key=statement", "Normal", false, ["Tree", "DFS"]),
new Problem("HE", "Birthday Gifts", "https://www.hackerearth.com/practice/math/combinatorics/inclusion-exclusion/practice-problems/algorithm/mancunian-and-birthday-gifts-d44faa15/description/", "Normal", false, ["Tree", "PIE"], ""),
new Problem("CSA", "Tree Construction", "contest/860/problem/D", "Hard", false, ["Tree", "DFS"], "several cases"),
],
general: [
@ -51,12 +52,6 @@ export const metadata = {
<problems-list problems={metadata.problems.sample} />
<info-block title="Pro Tip">
Quite frequent at the Silver level.
</info-block>
## Tutorial
- Recommended:

View file

@ -3,8 +3,7 @@ id: cyc
title: Cycle Detection
author: Siyong Huang
prerequisites:
- Silver - Functional Graphs
- Gold - Breadth First Search
- Gold - Topological Sort
description: A simple cycle is a non-empty path of distinct edges that start and end at the same vertex such that no vertex appears more than once. Describes how to detect cycles in both directed and undirected graphs.
frequency: 0
---
@ -32,13 +31,17 @@ export const metadata = {
<problems-list problems={metadata.problems.und} />
BFS-Cycle?
<optional-content title="+1 Approximation for Shortest Cycle">
An algorithm known as **BFS-Cycle** returns an integer that is at most one more than the length of the shortest cycle in $O(N^2)$ time; see page 4 [here](https://people.csail.mit.edu/virgi/6.890/lecture9.pdf) for details.
</optional-content>
## Directed Graphs
<problems-list problems={metadata.problems.dir} />
The same general idea is implemented below to find any cycle in a directed graph (if one exists).
The same general idea is implemented below to find any cycle in a directed graph (if one exists). Note that this is almost identical to the DFS algorithm for topological sorting.
```cpp
//UNTESTED

View file

@ -62,19 +62,13 @@ Usually, at least one problem from every gold division contest involves some sor
The following tutorials serve as an introduction into the mindset of DP.
<resources>
<resource source="CPH" title="CPH 7" starred>Great introduction that covers most classical problems</resource>
<resource source="Topcoder" title="DP from Novice to Advanced">great for all skill levels</resource>
<resource source="CPH" title="7 - DP" starred>great introduction that covers most classical problems</resource>
<resource source="TC" title="DP from Novice to Advanced" url="dynamic-programming-from-novice-to-advanced">great for all skill levels</resource>
<resource source="CPC" title="6 - DP" url="06_dynamic_programming">examples with nonclassical problems</resource>
<resource source="HR" title="DP" url="https://www.hackerrank.com/topics/dynamic-programming">also covers many classical problems</resource>
<resource source="PAPS" title="9 - DP">starts with DAGs, which are covered in "Topological Sort"</resource>
</resources>
- CPH 7
- great introduction that covers most classical problems
- [Topcoder DP](https://www.topcoder.com/community/competitive-programming/tutorials/dynamic-programming-from-novice-to-advanced/)
- great for all skill levels
- [CPC.6](https://github.com/SuprDewd/T-414-AFLV/tree/master/06_dynamic_programming)
- examples with nonclassical problems
- [HackerRank DP](https://www.hackerrank.com/topics/dynamic-programming)
- also covers many classical problems
Practice makes perfect. Start by doing some classical problems (try at least one of each), as these are **must know** DP problems. Each topic starts with direct applications of the classical problems, and then some interesting variations and USACO problems which utilize the ideas. Solutions for most problems (excluding USACO) can be found on Chapter 7 of CPH.
<info-block title="Pro Tip">
@ -103,10 +97,9 @@ Sometimes it's a good idea to write a slower polynomial-time solution and then o
DP is a very important topic, so you should do a lot of practice on it.
- [**Atcoder DP Contest**](https://atcoder.jp/contests/dp/tasks)
- very good!
- [CSES DP Section](https://cses.fi/problemset/list/)
- also very good!
- [Codeforces DP Problem List](http://codeforces.com/blog/entry/325)
<resources>
<resource source="AC" title="DP Contest" url="https://atcoder.jp/contests/dp/tasks" starred>very good!</resource>
<resource source="CSES" title="DP Section" url="https://cses.fi/problemset/list/" starred>also very good!</resource>
<resource source="CF" title="DP List" url="blog/entry/325">misc probs, a lot of which you don't need to know at this level</resource>
</resources>

View file

@ -22,6 +22,7 @@ export const metadata = {
],
rollback: [
new Problem("YS", "Persistent Union Find", "persistent_unionfind", "Normal", false, [], ""),
new Problem("YS", "Vertex Add Component Sum", "dynamic_graph_vertex_add_component_sum", "Hard", false, [], ""),
new Problem("CF", "Edu F - Extending Set of Points", "contest/1140/problem/F", "Hard", false, [], ""),
],
}
@ -31,12 +32,14 @@ export const metadata = {
## Tutorial
- CPH 15.2
- [PAPS 11.1](https://www.csc.kth.se/~jsannemo/slask/main.pdf)
- Chapter 10.6 of "An Introduction to the US Computing Olympiad"
- [CSAcademy Disjoint-Set](https://csacademy.com/lesson/disjoint_data_sets)
- [Topcoder Union Find](https://www.topcoder.com/community/data-science/data-science-tutorials/disjoint-set-data-structures/)
- [CPC.3](https://github.com/SuprDewd/T-414-AFLV/tree/master/03_data_structures)
<resources>
<resource source="CPH" title="15.2 - Union-find"></resource>
<resource source="PAPS" title="11.1"></resource>
<resource source="IUSACO" title="10.6"></resource>
<resource source="CSA" title="Disjoint Data Sets" url="disjoint_data_sets"></resource>
<resource source="TC" title="Disjoint Set Data Structures" url="disjoint-set-data-structures"></resource>
<resource source="CPC" title="3 - Data Structures" url="03_data_structures"></resource>
</resources>
<optional-content title="DSU Complexity Proofs">
@ -45,6 +48,8 @@ export const metadata = {
</optional-content>
Note: You may prefer to use this in place of DFS for computing connected components.
## Problems
<problems-list problems={metadata.problems.general} />
@ -54,5 +59,3 @@ export const metadata = {
no path compression
<problems-list problems={metadata.problems.rollback} />
https://judge.yosupo.jp/problem/dynamic_graph_vertex_add_component_sum

View file

@ -1,35 +0,0 @@
---
id: hashing
title: "Hashing"
author: Benjamin Qi
description: Quickly test equality of substrings with a small probability of failure.
frequency: 1
---
## Tutorial
- [PAPS 14.3](https://www.csc.kth.se/~jsannemo/slask/main.pdf)
- CPH 26.3
- [cp-algorithms String Hashing](https://cp-algorithms.com/string/string-hashing.html)
My implementation can be found [here](https://github.com/bqi343/USACO/blob/master/Implementations/content/strings%20(14)/Light/HashRange%20(14.2).h). It uses two bases rather than just one to decrease the probability that two random strings hash to the same value. As mentioned in the articles above, there is no need to calculate modular inverses.
## Hacking
- [Anti-Hash Tests](https://codeforces.com/blog/entry/60442)
- On CodeForces educational rounds in particular, make sure to use random bases.
## Problems
- USACO
- [Gold Cownomics](http://www.usaco.org/index.php?page=viewproblem2&cpid=741)
- Use two pointers; for a fixed $l$, keep extending $r$ to the right until the positions $l\ldots r$ explain spotiness.
- Hashing gives you a way to quickly check whether two substrings of different cow types are equal. So for a single $[l,r]$ pair you can check whether it works in $O(N\log N)$ time (and you only need to check $O(M)$ of these pairs in total).
- Actually, it's possible to pass $O(N^2M)$ (or even slower) solutions.
- [Gold Lightsout](http://www.usaco.org/index.php?page=viewproblem2&cpid=599)
- figure out whether this actually needs hashing? (check ...)
- Other (check ...)
- [Palindromic Partitions](https://csacademy.com/contest/ceoi-2017-day-2/task/palindromic-partitions/)
- [Liar](http://codeforces.com/problemset/problem/822/E) [](93)
- [Palindromic Characteristics](http://codeforces.com/problemset/problem/835/D) [](100)
- [Berland SU Computer Network](http://codeforces.com/contest/847/problem/L) [](142)

View file

@ -21,6 +21,7 @@ export const metadata = {
new Problem("Old Silver", "SuperBull", "531", "Easy", false, ["MST"], ""),
new Problem("Gold", "Walk", "946", "Easy", false, ["Math","Prim"], ""),
new Problem("Gold", "Fencedin", "623", "Easy", false, ["MST"], ""),
new Problem("HR", "Spanning Tree Fraction", "https://www.hackerrank.com/contests/w31/challenges/spanning-tree-fraction/problem", "Easy", false, ["MST", "Binary Search"], ""),
new Problem("Plat", "Fencedin", "625", "Normal", false, ["Kruskal"], ""),
],
}
@ -32,20 +33,14 @@ export const metadata = {
## Tutorial
- CPH 15 (Spanning Trees)
- [PAPS 12.4](https://www.csc.kth.se/~jsannemo/slask/main.pdf)
- Prim's Algorithm
- [cp-algo](https://cp-algorithms.com/graph/mst_prim.html)
- Similar to Dijkstra
- Kruskal's Algorithm
- [cp-algo 1](https://cp-algorithms.com/graph/mst_kruskal.html)
- [cp-algo 2](https://cp-algorithms.com/graph/mst_kruskal_with_dsu.html)
<resources>
<resource source="CPH" title="15 - Spanning Trees" starred>Kruskal's & Prim's</resource>
<resource source="PAPS" title="12.4">Kruskal's</resource>
<resource source="cp-algo" title="Prim's" url="graph/mst_prim.html"></resource>
<resource source="cp-algo" title="Kruskal's" url="graph/mst_kruskal.html"></resource>
<resource source="cp-algo" title="Kruskal's" url="graph/mst_kruskal_with_dsu.html"></resource>
</resources>
## USACO Gold Problems
## USACO Problems
<problems-list problems={metadata.problems.general} />
## Other Problems
- [Birthday Gifts](https://www.hackerearth.com/practice/math/combinatorics/inclusion-exclusion/practice-problems/algorithm/mancunian-and-birthday-gifts-d44faa15/) [](73)
- [Spanning Tree Fraction](https://www.hackerrank.com/contests/w31/challenges/spanning-tree-fraction) [](78)
<problems-list problems={metadata.problems.general} />

View file

@ -14,7 +14,7 @@ export const metadata = {
sample: [
new Problem("YS", "Point Set Range Composite", "point_set_range_composite", "Intro", false, ["PURQ"], ""),
],
probs: [
general: [
new Problem("CSES", "Range Minimum Queries II", "1649", "Intro", false, ["PURQ"], ""),
new Problem("Gold", "Springboards", "995", "Normal", false, ["PURQ"], "min segtree"),
new Problem("Plat", "Nocross", "721", "Normal", false, ["PURQ"], "LIS variation"),
@ -24,6 +24,8 @@ export const metadata = {
<problems-list problems={metadata.problems.sample} />
<br/>
A **segment tree** allows you to do point update and range query in $O(\log N)$ time each for any associative operation.
<info-block title="Pro Tip">
@ -34,12 +36,14 @@ For gold, you only need to know the basics (ex. sum, min queries). More advanced
### Tutorials
- CPH 9.3 (Segment Trees)
- [PAPS 11.2.3](https://www.csc.kth.se/~jsannemo/slask/main.pdf)
- [Codeforces Tutorial](http://codeforces.com/blog/entry/18051)
- [CSAcademy Tutorial](https://csacademy.com/lesson/segment_trees/)
- [cp-algorithms](https://cp-algorithms.com/data_structures/segment_tree.html)
- [Slides from CPC.3](https://github.com/SuprDewd/T-414-AFLV/tree/master/03_data_structures)
<resources>
<resource source="CSA" title="Segment Trees" url="segment_trees" starred>interactive</resource>
<resource source="CF" title="Efficient and easy segment trees" url="blog/entry/18051" starred>simple implementation</resource>
<resource source="CPH" title="9.3 - Segment Trees" starred>same implementation as above</resource>
<resource source="cp-algo" title="Segment Tree" url="data_structures/segment_tree.html"></resource>
<resource source="PAPS" title="11.2.3"></resource>
<resource source="CPC" title="3 - Data Structures" url="03_data_structures"></resource>
</resources>
### Problems

View file

@ -53,13 +53,12 @@ Aka *Fenwick Tree*.
### Tutorials
* CPH 9.2, 9.4
* very good
* [CSAcademy BIT](https://csacademy.com/lesson/fenwick_trees)
* also very good
* [cp-algorithms Fenwick Tree](https://cp-algorithms.com/data_structures/fenwick.html)
* extends to range increment and range query, although this is not necessary for gold
* [Topcoder BIT](https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/)
<resources>
<resource source="CSA" title="Fenwick Trees" url="fenwick_trees" starred>interactive</resource>
<resource source="CPH" title="9.2, 9.4 - Binary Indexed Tree" starred>similar to above</resource>
<resource source="cp-algo" title="Fenwick Tree" url="data_structures/fenwick.html">also similar to above</resource>
<resource source="TC" title="Binary Indexed Trees" url="binary-indexed-trees"></resource>
</resources>
My implementation can be found [here](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BIT%20(9.2).h), and can compute range sum queries for any number of dimensions.

View file

@ -43,12 +43,12 @@ Use *Dijkstra's Algorithm*.
### Tutorial
- CSES 13.2
- [PAPS 12.3.1](https://www.csc.kth.se/~jsannemo/slask/main.pdf)
- [cp-algo Dijkstra (Dense Graphs)](https://cp-algorithms.com/graph/dijkstra_sparse.html)
- [cp-algo Dijkstra (Sparse Graphs)](https://cp-algorithms.com/graph/dijkstra_sparse.html)
- Usually, it's this one that's applicable.
- [CPC.8](https://github.com/SuprDewd/T-414-AFLV/tree/master/08_graphs_2)
<resources>
<resource source="CPH" title="13.2 - Dijkstra" starred>code</resource>
<resource source="cp-algo" title="Dijkstra (Dense Graphs)" url="graph/dijkstra_dense.html"></resource>
<resource source="cp-algo" title="Dijkstra (Sparse Graphs)" url="graph/dijkstra_sparse.html"></resource>
<resource source="CPC" title="8 - Graphs 2" url="08_graphs_2"></resource>
</resources>
### $O(M\log N)$ implementation
@ -72,19 +72,30 @@ Can be done in $O(M+N\log N)$ with Fibonacci heap.
Use the *Floyd-Warshall* algorithm.
### Standard
- [CSES Shortest Routes II](https://cses.fi/problemset/task/1672)
### Tutorial
- CPH 13.3
- [PAPS 12.3.3](https://www.csc.kth.se/~jsannemo/slask/main.pdf)
- [cp-algo Floyd-Warshall](https://cp-algorithms.com/graph/all-pair-shortest-path-floyd-warshall.html)
<resources>
<resource source="CPH" title="13.3 - Floyd-Warshall" starred>example calculation, code</resource>
<resource source="PAPS" title="12.3.3"></resource>
<resource source="cp-algo" title="Floyd-Warshall" url="graph/all-pair-shortest-path-floyd-warshall.html"></resource>
</resources>
<optional-content title="Incorrect Floyd-Warshall">
[Paper](https://arxiv.org/pdf/1904.01210.pdf)
> A common mistake in implementing the FloydWarshall algorithm is to
misorder the triply nested loops (The correct order is `KIJ`). The incorrect
`IJK` and `IKJ` algorithms do not give correct solutions for some instance. However, we can prove that if these are repeated three times, we obtain the correct solutions.
>
> It would be emphasized that these fixes (repeating incorrect algorithms three
times) have the same time complexity as the correct FloydWarshall algorithm
up to constant factors. Therefore, our results suggest that, if one is confused by
the order of the triply nested loops, one can repeat the procedure three times
just to be safe.
</optional-content>
### Problems
<problems-list problems={metadata.problems.apsp} />
- [USACO Moortal Cowmbat](http://usaco.org/index.php?page=viewproblem2&cpid=971)
- Use APSP before running DP.
<problems-list problems={metadata.problems.apsp} />

View file

@ -10,7 +10,7 @@ import { Problem } from "../models";
export const metadata = {
problems: {
rmqSample: [
new Problem("YS", "Static RMQ", "staticrmq", "Easy", false, []),
new Problem("YS", "Static RMQ", "staticrmq", "Easy", false, [], "equivalent to [CSES Range Minimum Queries I](https://cses.fi/problemset/task/1647)"),
],
diviSample: [
new Problem("ojuz", "JOI Secret", "JOI14_secret", "Easy", false, [], ""),
@ -33,18 +33,18 @@ With $O(N\log N)$ time preprocessing, we can get $O(1)$ queries.
First we'll consider the special case when $\ominus$ denotes `min`.
- [CSES Range Minimum Queries I](https://cses.fi/problemset/task/1647)
### Tutorial
- CPH 9.1
- [PAPS 11.2.2](https://www.csc.kth.se/~jsannemo/slask/main.pdf)
- [cp-algo RMQ](https://cp-algorithms.com/sequences/rmq.html)
- [cp-algo Sparse Table](https://cp-algorithms.com/data_structures/sparse-table.html)
<resources>
<resource source="CPH" title="9.1 - Minimum Queries" starred>diagrams</resource>
<resource source="PAPS" title="11.2.2 - Sparse Tables" starred>code</resource>
<resource source="cp-algo" title="RMQ" url="sequences/rmq.html"></resource>
<resource source="cp-algo" title="Sparse Table" url="data_structures/sparse-table.html"></resource>
</resources>
<optional-content title="Preprocessing in O(N) Time">
<optional-content title="Faster Preprocessing">
- [CF: $O(1)$ Query RMQ with $O(N)$ build](https://codeforces.com/blog/entry/78931)
[CF: $O(1)$ Query RMQ with $O(N)$ build](https://codeforces.com/blog/entry/78931)
</optional-content>

View file

@ -13,6 +13,9 @@ import { Problem } from "../models";
export const metadata = {
problems: {
sample: [
new Problem("Gold", "Springboards", "995", "Hard", false, [], ""),
],
problems: [
new Problem("CF", "Karen & Cards", "contest/815/problem/D", "Very Hard", false, [], "For each a from p to 1, calculate the number of possible cards with that value of a."),
new Problem("CF", "GP of Korea 19 - Interesting Drug", "gym/102059/problem/K", "Very Hard", false, [], "Genfuncs not required but possibly helpful"),
@ -20,7 +23,11 @@ export const metadata = {
}
};
To solve USACO Gold [Springboards](http://www.usaco.org/index.php?page=viewproblem2&cpid=995), we need a data structure that supports operations similar to the following:
<problems-list problems={metadata.problems.sample} />
<br/>
To solve this problem, we need a data structure that supports operations similar to the following:
1. Add a pair $(a,b)$.
2. For any $x$, query the maximum value of $b$ over all pairs satisfying $a\ge x$.

View file

@ -0,0 +1,61 @@
---
id: hashing
title: "Hashing"
author: Benjamin Qi
description: Quickly test equality of substrings with a small probability of failure.
frequency: 1
---
import { Problem } from "../models";
export const metadata = {
problems: {
ex: [
new Problem("Gold", "Cownomics", "741", "Easy", false, [], ""),
],
general: [
new Problem("CSA", "Palindromic Partitions", "palindromic-partitions", "Easy", false, ["Greedy", "Hashing"], ""),
new Problem("CF", "Palindromic Characteristics", "problemset/problem/835/D", "Easy", false, ["DP", "Hashing"], ""),
new Problem("CF", "Liar", "problemset/problem/822/E", "Hard", false, ["DP", "Hashing"], ""),
],
adj: [
new Problem("CF", "Berland SU Computer Network", "contest/847/problem/L", "Normal", false, [], ""),
]
}
};
## Tutorial
<resources>
<resource source="CPH" title="26.3 - String Hashing" starred>good intro</resource>
<resource source="cp-algo" title="String Hashing" url="string/string-hashing.html" starred>code</resource>
<resource source="PAPS" title="14.3 - Hashing" starred>many applications</resource>
</resources>
My implementation can be found [here](https://github.com/bqi343/USACO/blob/master/Implementations/content/strings%20(14)/Light/HashRange%20(14.2).h). It uses two bases rather than just one to decrease the probability that two random strings hash to the same value. As mentioned in the articles above, there is no need to calculate modular inverses.
## Example: Cownomics (Gold)
<problems-list problems={metadata.problems.ex} />
- Use two pointers; for a fixed $l$, keep extending $r$ to the right until the positions $l\ldots r$ explain spotiness.
- Hashing gives you a way to quickly check whether two substrings of different cow types are equal. So for a single $[l,r]$ pair you can check whether it works in $O(N\log N)$ time (and you only need to check $O(M)$ of these pairs in total).
- Actually, it's possible to pass $O(N^2M)$ (or even slower) solutions.
## Adjacency Lists
(elaborate)
<problems-list problems={metadata.problems.adj} />
## Hacking
<resources>
<resource source="CF" title="dacin21 - Anti-Hash Tests" url="blog/entry/60442">On CodeForces educational rounds in particular, make sure to randomize your bases.</resource>
</resources>
## Problems
<problems-list problems={metadata.problems.general} />

View file

@ -16,6 +16,9 @@ export const metadata = {
sample: [
new Problem("CSES", "Course Schedule", "1679", "Easy", false, []),
],
dp: [
new Problem("CSES", "Longest Flight Route", "1680", "Easy", false, []),
],
general: [
new Problem("CSES", "Game Routes", "1681", "Easy", false, [], "counting paths on DAG"),
new Problem("Kattis", "Quantum", "https://open.kattis.com/contests/acpc17open/problems/quantumsuperposition", "Easy", false, [], "enumerating paths on DAG"),
@ -34,24 +37,38 @@ To review, a **directed** graph consists of edges that can only be traversed in
A [topological sort](https://en.wikipedia.org/wiki/Topological_sorting) of a directed acyclic graph is a linear ordering of its vertices such that for every directed edge $u\to v$ from vertex $u$ to vertex $v$, $u$ comes before $v$ in the ordering.
### Tutorial
## Tutorial
- CPH 16.1, 16.2
- DFS
- [cp-algorithms](https://cp-algorithms.com/graph/topological-sort.html)
- DFS
- [CSAcademy](https://csacademy.com/lesson/topological_sorting)
- both BFS, DFS
<resources>
<resource source="CSA" title="Topological Sorting" url="topological_sorting" starred>both BFS, DFS</resource>
</resources>
### DFS
<resources>
<resource source="CPH" title="16.1, 16.2 - Topological Sorting">DFS</resource>
<resource source="cp-algo" title="Topological Sort" url="graph/topological-sort.html">DFS</resource>
</resources>
(implementation)
### BFS
The BFS version, known as [Kahn's Algorithm](https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm), makes it obvious how to extract the lexicographically minimum topological sort.
(implementation)
## Dynamic Programming
- [PAPS 9.1](https://www.csc.kth.se/~jsannemo/slask/main.pdf)
<resources>
<resource source="PAPS" title="9.1">Best Path in a DAG</resource>
</resources>
One useful property of directed acyclic graphs is, as the name suggests, that there exists no cycles. If we consider each node in the graph as a state, we can perform dynamic programming on the graph if we process the states in an order that guarantees for every edge, $u\to v$ that $u$ is processed before $v$. Fortunately, this is the exact definition of a topological sort!
One useful property of directed acyclic graphs is, as the name suggests, that no cycles exist. If we consider each node in the graph as a state, we can perform dynamic programming on the graph if we process the states in an order that guarantees for every edge $u\to v$ that $u$ is processed before $v$. Fortunately, this is the exact definition of a topological sort!
Let's consider the classical problem [CSES Longest Flight Route](https://cses.fi/problemset/task/1680), where we must find the longest path in a DAG.
<problems-list problems={metadata.problems.dp} />
In this task, we must find the longest path in a DAG.
<spoiler title="Solution">
@ -63,6 +80,7 @@ $$
or zero if $v$ has in-degree $0$. If we process the states in topological order, it is guarangeed that $dp[u]$ will already have been computed before computing $dp[v]$.
(implementation?)
</spoiler>
<!-- However, not all problems clearly give you directed acyclic graphs (ex. [Plat - Cave Paintings](http://usaco.org/index.php?page=viewproblem2&cpid=996)). An important step in many problems is to reduce the statement into a directed acyclic graph. See the editorial of the linked problem for more information.

View file

@ -1,12 +1,12 @@
---
id: tree-euler
title: "Euler Tour on Tree"
title: "Euler Tour Technique"
author: "?"
prerequisites:
- Silver - Depth First Search
- Gold - Static Range Queries
- Gold - Point Update Range Sum
description: Subtree updates and queries as well as a way to compute lowest common ancestors.
description: Flattening a tree into an array.
frequency: 2
---
@ -16,13 +16,13 @@ export const metadata = {
problems: {
sample: [
new Problem("CSES", "Subtree Queries", "1137", "Easy", false, ["Euler-Tree"], "equivalent to https://judge.yosupo.jp/problem/vertex_add_subtree_sum"),
new Problem("CSES", "Path Queries", "1138", "Easy", false, ["Euler-Tree","PURS"], "equivalent to https://judge.yosupo.jp/problem/vertex_add_path_sum"),
],
lca: [
new Problem("CSES", "Company Queries II", "1688", "Easy", false, ["LCA"], ""),
new Problem("CSES", "Distance Queries", "1135", "Easy", false, ["LCA"], ""),
],
problems: [
new Problem("CSES", "Distance Queries", "1135", "Easy", false, ["LCA"], ""),
new Problem("CSES", "Path Queries", "1138", "Easy", false, ["Euler-Tree","PURS"], "equivalent to https://judge.yosupo.jp/problem/vertex_add_path_sum"),
new Problem("Gold", "Cow Land", "921", "Normal", false, ["Euler-Tree","PURS", "HLD"], ""),
new Problem("Gold", "Milk Visits", "970", "Normal", false, ["Euler-Tree", "LCA"], ""),
new Problem("Plat", "Promotion Counting", "696", "Normal", false, ["Euler-Tree","PURS"], ""),
@ -36,16 +36,24 @@ export const metadata = {
<problems-list problems={metadata.problems.sample} />
If we can preprocess a rooted tree such that every subtree corresponds to a contiguous range on an array, we can do updates and range queries on it!
### Tutorial
- CPH 18.2 - Subtrees & Paths
<resources>
<resource source="CPH" title="18.2 - Subtrees & Paths" starred>introduces tree traversal array</resource>
</resources>
## LCA
<problems-list problems={metadata.problems.lca} />
### Tutorial
- CPH 18.3 - Least Common Ancestor
- [cp-algorithms - LCA with Sparse Table](https://cp-algorithms.com/graph/lca.html)
<resources>
<resource source="CPH" title="18.3 - Least Common Ancestor (Method 2)" starred></resource>
<resource source="cp-algo" title="Reducing LCA to RMQ" url="graph/lca.html" starred></resource>
</resources>
(implementation)

View file

@ -8,6 +8,17 @@ description: "Extending Range Queries to 2D (and beyond)."
frequency: 1
---
export const metadata = {
problems: {
bitSam: [
new Problem("CSES", "Forest Queries II", "1739", "Easy", false, ["2D BIT"], "[thecodingwizard's implementation](https://github.com/thecodingwizard/competitive-programming/blob/master/cses/Forest%20Queries%20II.cpp)"),
],
offSam: [
new Problem("DMOJ", "Soriya's Programming Project", "dmopc19c7p5", "Normal", false, ["2D BIT"], ""),
]
}
};
See [my implementations](https://github.com/bqi343/USACO/tree/master/Implementations/content/data-structures/2D%20Range%20Queries%20(15.2)).
## Static Array Queries
@ -17,16 +28,12 @@ See [my implementations](https://github.com/bqi343/USACO/tree/master/Implementat
## 2D BIT
<problems-list problems={metadata.problems.bitSam} />
### Tutorials
- [GFG 2D BIT](https://www.geeksforgeeks.org/two-dimensional-binary-indexed-tree-or-fenwick-tree/)
- [TopCoder BIT](https://www.topcoder.com/community/competitive-programming/tutorials/binary-indexed-trees/)
- Suppose that you want to update $N\approx 10^5$ points with both coordinates in the range $[1,N]$.
- The 2D BITs mentioned above use $O(N^2)$ memory, which is too much.
- Can be reduced to $O(N\log^2N)$ memory with unordered map, but this might also be too much (and too slow).
- If you know the points to be updated beforehand then you can reduce to $O(N\log N)$ memory (and no maps).
- [my 1D offline BIT](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BIToff.h)
- [my 2D offline BIT](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/2D%20Range%20Queries%20(15.2)/BIT2DOff%20(15.2).h)
<optional-content title="Range Update and Range Query in Higher Dimensions">
@ -37,23 +44,35 @@ You can extend the 1D BIT solution for range update range query to higher dimens
</optional-content>
### Offline
Suppose that you want to update and query with $N\approx 10^5$ points.
- The 2D BITs mentioned above use $O(N^2)$ memory, which is too much.
- Can be reduced to $O(N\log^2N)$ memory with unordered map, but this might also be too much (and too slow).
- If you know the points to be updated beforehand then you can reduce to $O(N\log N)$ memory (and no maps).
- [my 1D offline BIT](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BIToff.h)
- [my 2D offline BIT](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/2D%20Range%20Queries%20(15.2)/BIT2DOff%20(15.2).h)
<problems-list problems={metadata.problems.offSam} />
The intended complexity is $O(N\log^2 N)$. Two options:
- compressed 2D BIT
- rather difficult to pass within time and memory limits
- Make sure to use `\n` instead of `endl`!
- [thecodingwizard's implementation with Benq's 2d offline bit](https://github.com/thecodingwizard/competitive-programming/blob/master/DMOJ/Soriyas%20Programming%20Project.cpp)
- divide & conquer with a 1D BIT
- mentioned [here](https://robert1003.github.io/2020/01/31/cdq-divide-and-conquer.html).
- [thecodingwizard's (messy) implementation](https://github.com/thecodingwizard/competitive-programming/blob/master/DMOJ/Soriya%20Programming%20Project%201d%20BIT%20cdq%20dnc.cpp) based off of article above
### Problems
- [CSES Forest Queries II](https://cses.fi/problemset/task/1739)
- [thecodingwizard's implementation](https://github.com/thecodingwizard/competitive-programming/blob/master/cses/Forest%20Queries%20II.cpp)
- [DMOJ Soriya's Programming Project](https://dmoj.ca/problem/dmopc19c7p5)
- intended complexity is $O(N\log^2 N)$
- compressed 2D BIT
- rather difficult to pass within time and memory limits
- Make sure to use `\n` instead of `endl`!
- [thecodingwizard's implementation with Benq's 2d offline bit](https://github.com/thecodingwizard/competitive-programming/blob/master/DMOJ/Soriyas%20Programming%20Project.cpp)
- or do divide & conquer with a 1D BIT
- same as first problem [here](https://robert1003.github.io/2020/01/31/cdq-divide-and-conquer.html)
- [thecodingwizard's (messy) implementation](https://github.com/thecodingwizard/competitive-programming/blob/master/DMOJ/Soriya%20Programming%20Project%201d%20BIT%20cdq%20dnc.cpp) based off of article above
- [IOI 2007 Pairs](https://wcipeg.com/problem/ioi0722)
- [DMOJ Crowded Cities](https://dmoj.ca/problem/bfs17p6)
- [USACO Plat Friendcross](http://www.usaco.org/index.php?page=viewproblem2&cpid=722)
- [USACO Plat Mowing](http://www.usaco.org/index.php?page=viewproblem2&cpid=601)
- [IOI 2007 Pairs](https://wcipeg.com/problem/ioi0722)
- [DMOJ Crowded Cities](https://dmoj.ca/problem/bfs17p6)
- [USACO Plat Friendcross](http://www.usaco.org/index.php?page=viewproblem2&cpid=722)
- [USACO Plat Mowing](http://www.usaco.org/index.php?page=viewproblem2&cpid=601)
## 2D Segment Tree

View file

@ -42,8 +42,10 @@ export const metadata = {
### Tutorial
- CPH 18.1, 18.3
- [cp-algorithms](https://cp-algorithms.com/)
<resources>
<resource source="CPH" title="18.1, 18.3 (Method 1) - Finding Ancestors" starred></resource>
<resource source="cp-algo" title="LCA with Binary Lifting" url="graph/lca_binary_lifting.html"> </resource>
</resources>
<optional-content title="Improvements">

View file

@ -33,10 +33,11 @@ export const metadata = {
## Tutorial
tl;dr some operations are 32x-64x faster compared to a boolean array.
tl;dr some operations are 32x-64x faster compared to a boolean array. See the [C++ Reference](http://www.cplusplus.com/reference/bitset/bitset/) for the operations you can perform.
- [C++ Reference](http://www.cplusplus.com/reference/bitset/bitset/)
- [Errichto - Bitwise Operations Pt 2](https://codeforces.com/blog/entry/73558)
<resources>
<resource source="CF" title="Errichto - Bitwise Operations Pt 2" url="blog/entry/73558"></resource>
</resources>
## Knapsack

View file

@ -26,8 +26,10 @@ export const metadata = {
### Tutorial
- [GeeksForGeeks](http://www.geeksforgeeks.org/centroid-decomposition-of-tree/)
- [Carpanese](https://medium.com/carpanese/an-illustrated-introduction-to-centroid-decomposition-8c1989d53308)
<resources>
<resource source="Carpanese" title="Illustrated Intro to Centroid Decomposition" url="https://medium.com/carpanese/an-illustrated-introduction-to-centroid-decomposition-8c1989d53308" starred></resource>
<resource source="GFG" title="Centroid Decomposition of Tree" url="centroid-decomposition-of-tree"></resource>
</resources>
### Problems

View file

@ -2,7 +2,7 @@
id: geo-pri
title: "Geometry Primitives"
author: Benjamin Qi
description: Basic setup for geometry problems and introduction to line sweep.
description: Basic setup for geometry problems.
---
## Primitives
@ -11,21 +11,20 @@ You should know basic operations like cross product and dot product. For platinu
### Tutorial
- [CPC.12](https://github.com/SuprDewd/T-414-AFLV/tree/master/12_geometry)
- basic geometry
- convex hulls
- polygon area
- point in polygon
- CPH 29 (Geometry), 30.1, 30.2 (Sweep line algorithms)
- [TopCoder - Basic Geometry Concepts](https://www.topcoder.com/community/competitive-programming/tutorials/geometry-concepts-basic-concepts/)
- [CF - Point Class](https://codeforces.com/blog/entry/48122)
- [C++ - std::complex](https://codeforces.com/blog/entry/22175)
- [cp-algo - Geometry: "Elementary Operations"](https://cp-algorithms.com/)
- [vlecomte - Geometry Handbook](https://codeforces.com/blog/entry/59129)
- [My Templates](https://github.com/bqi343/USACO/tree/master/Implementations/content/geometry%20(13)/Primitives)
<resources>
<resource source="CPC" title="12 - geometry" url="12_geometry">basics, polygon area, point in polygon</resource>
<resource source="CPH" title="29"></resource>
<resource source="TC" title="Basic Geometry Concepts" url="geometry-concepts-basic-concepts"></resource>
<resource source="CF" title="Point Class" url="blog/entry/48122"></resource>
<resource source="CF" title="C++ - std::complex" url="blog/entry/22175"></resource>
<resource source="cp-algo" title="Geometry - Elementary Operations" url="https://cp-algorithms.com/"></resource>
<resource source="CF" title="vlecomte - Geometry Handbook" url="blog/entry/59129"></resource>
</resources>
### Problems
- [My Templates](https://github.com/bqi343/USACO/tree/master/Implementations/content/geometry%20(13)/Primitives)
- Template Testing
- [yosupo: Sort Points by Arg](https://judge.yosupo.jp/problem/sort_points_by_argument)
- [Kattis Segment Distance](https://open.kattis.com/problems/segmentdistance)
@ -40,16 +39,3 @@ You should know basic operations like cross product and dot product. For platinu
- [Birthday Cake](https://open.kattis.com/problems/birthdaycake)
- [Racing Off Track](https://open.kattis.com/contests/acpc17open/problems/racingofftrack)
- [TopCoder Watchtower](https://community.topcoder.com/stat?c=problem_statement&pm=2014&rd=4685)
## Sweep Line
### Tutorial
- CPH 30
- [TopCoder Line Sweep](https://www.topcoder.com/community/competitive-programming/tutorials/line-sweep-algorithms/)
### Problems
- [Cow Steepchase II (Silver)](http://www.usaco.org/index.php?page=viewproblem2&cpid=943)
- :|
- [Kattis Closest Pair](https://open.kattis.com/problems/closestpair2)

View file

@ -3,7 +3,7 @@ id: hld
title: "Heavy-Light Decomposition"
author: Benjamin Qi
prerequisites:
- Gold - Euler Tour on Tree
- Gold - Euler Tour Technique
- Platinum - Range Update Range Query
description: Path and subtree updates and queries.
frequency: 1
@ -14,25 +14,28 @@ import { Problem } from "../models";
export const metadata = {
problems: {
sample: [
new Problem("CSES", "Company Queries II", "1688", "Easy", false, ["LCA"], ""),
new Problem("YS","Vertex Set Path Composite","vertex_set_path_composite", "Normal", false, ["HLD"], ""),
new Problem("CSES", "Company Queries II", "1688", "Intro", false, ["LCA"], ""),
new Problem("YS","Vertex Set Path Composite","vertex_set_path_composite", "Easy", false, ["HLD"], ""),
],
general: [
new Problem("Gold", "Cow Land", "921", "Normal", false, ["Euler-Tree","PURS", "HLD"], ""),
new Problem("Plat", "Disrupt", "842", "Easy", false, ["HLD"]),
new Problem("Gold", "Cow Land", "921", "Easy", false, ["Euler-Tree","PURS", "HLD"], ""),
new Problem("Plat", "Disrupt", "842", "Easy", false, ["HLD"], ""),
new Problem("Old Gold", "Grass Planting", "102", "Easy", false, ["HLD"], ""),
new Problem("HR", "Subtrees & Paths", "https://www.hackerrank.com/challenges/subtrees-and-paths", "Easy", false, ["HLD"], ""),
new Problem("ojuz", "JOI - Cats or Dogs", "https://oj.uz/problem/view/JOI18_catdog", "Hard", false, ["HLD"], ""),
],
}
};
<problems-list problems={metadata.problems.sample} />
(computing LCA, path composite)
## Tutorial
- [Anudeep2011](https://blog.anudeep2011.com/heavy-light-decomposition/)
- [AI-Cash](http://codeforces.com/blog/entry/22072)
- [adamant](https://codeforces.com/blog/entry/53170)
<resources>
<resource source="anudeep2011" title="HLD" url="https://blog.anudeep2011.com/heavy-light-decomposition/" starred>explains what HLD is (but incomplete & overly complicated code)</resource>
<resource source="CF" title="AI-Cash - HLD Implementation" url="blog/entry/22072" starred></resource>
<resource source="CF" title="adamant - Easiest HLD with subtree queries" url="blog/entry/53170" starred></resource>
</resources>
## Problems

View file

@ -2,28 +2,45 @@
id: LC
title: "LineContainer"
author: Benjamin Qi
description: Convex Container
description: Convex Containers
prerequisites:
- Platinum - Convex Hull
frequency: 1
---
## Half-Plane Intersection / Convex Stuff
import { Problem } from "../models";
export const metadata = {
problems: {
sample: [
new Problem("YS", "Line Add Get Min", "line_add_get_min", "Easy", false, [], ""),
],
probs: [
new Problem("YS", "Line Add Get Min", "segment_add_get_min", "Normal", false, [], ""),
new Problem("CSA", "Building Bridges", "building-bridges", "Normal", false, [], ""),
new Problem("Old Gold", "Fencing the Herd", "534", "Normal", false, [], ""),
]
}
};
## Half-Plane Intersection
- [Blogewoosh (Half-Plane Intersection w/ Ternary Search)](https://codeforces.com/blog/entry/61710)
- [retrograd Half-Plane Intersection](https://codeforces.com/blog/entry/61710?#comment-457662)
- [Petr (Linear Half-Plane Intersection)](https://petr-mitrichev.blogspot.com/2016/07/a-half-plane-week.html)
## LineContainer
<problems-list problems={metadata.problems.sample} />
- [KACTL LineContainer](https://github.com/kth-competitive-programming/kactl/blob/master/content/data-structures/LineContainer.h)
- [Lichao Segment Tree](http://codeforces.com/blog/entry/51275?#comment-351510)
- [retrograd Half-Plane Set](https://codeforces.com/blog/entry/61710?#comment-457662)
### Problems
## Problems
- https://judge.yosupo.jp/problem/line_add_get_min
- https://judge.yosupo.jp/problem/segment_add_get_min
- [Bridges](https://csacademy.com/contest/archive/task/building-bridges/)
- direct application of LineContainer
<problems-list problems={metadata.problems.probs} />
- [USACO Old Gold - Fencing](http://www.usaco.org/index.php?page=viewproblem2&cpid=534)
(add ICPC probs)
(add ICPC probs?)
TOKI problem

View file

@ -1,20 +1,43 @@
---
id: lagrange
title: "Lagrangian Relaxation (aka Aliens Trick)"
title: "Lagrangian Relaxation"
author: Benjamin Qi
description: "?"
description: "aka Aliens Trick"
prerequisites:
- Plat - Convex Hull
---
import { Problem } from "../models";
export const metadata = {
problems: {
sample: [
new Problem("Plat", "Tall Barn", "697", "Easy", false, [], ""),
],
probs: [
new Problem("ojuz", "Aliens", "IOI16_aliens", "Hard", false, [], ""),
]
}
};
aka just binary search on derivative
https://codeforces.com/contest/1344/problem/D
<problems-list problems={metadata.problems.sample} />
IOI 2016 Aliens
## Tutorial
tallbarn
<resources>
<resource source="Mamnoon Siam" title="Attack on Aliens" url="https://mamnoonsiam.github.io/posts/attack-on-aliens.html"></resource>
</resources>
CF prob
## Problems
300iq contest 2 insane prob(s)
<problems-list problems={metadata.problems.probs} />
Edu CF prob
CSA prob
MST K White
300iq contest 2 insane prob(s)

View file

@ -24,10 +24,12 @@ export const metadata = {
## Additional Reading
- CPH 18.4 - Merging Data Structures
- CF Blogs
- [Arpa](https://codeforces.com/blog/entry/44351)
- [tuwuna](https://codeforces.com/blog/entry/67696)
<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

View file

@ -25,11 +25,13 @@ export const metadata = {
new Problem("YS", "Range Affine Range Sum", "range_affine_range_sum", "Easy", false, ["Lazy SegTree"], ""),
new Problem("Plat", "Counting Haybales", "578", "Easy", false, ["Lazy SegTree"], ""),
new Problem("Old Gold", "The Lazy Cow", "418", "Easy", false, ["Lazy SegTree"], ""),
new Problem("CSES", "Area of Rectangles", "1741", "Hard", false, ["Lazy SegTree"], "use segment tree that keeps track of minimum and # of minimums"),
],
lazySegCnt: [
new Problem("CSES", "Area of Rectangles", "1741", "Hard", false, ["Lazy SegTree"], ""),
new Problem("HR", "Strange Tree", "https://www.hackerrank.com/contests/openbracket-2017/challenges/special-path-on-a-strange-tree/problem", "Hard", false, ["Lazy SegTree"]),
],
segTreeBeats: [
new Problem("YS", "Range Chmin Chmax Add Range Sum", "range_chmin_chmax_add_range_sum", "Hard", false, ["SegTreeBeats"], ""),
new Problem("YS", "Range Chmin Chmax Add Range Sum", "range_chmin_chmax_add_range_sum", "Very Hard", false, ["SegTreeBeats"], ""),
],
}
};
@ -42,9 +44,12 @@ Binary Indexed Trees can support range increments in addition to range sum queri
### Tutorial
- [GFG Range Update Point Query](https://www.geeksforgeeks.org/binary-indexed-tree-range-updates-point-queries/)
- [GFG Range Update Range Query](https://www.geeksforgeeks.org/binary-indexed-tree-range-update-range-queries/)
- [My Implementation](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BITrange.h)
<resources>
<resource source="GFG" title="Range Update Point Query" url="binary-indexed-tree-range-updates-point-queries/"></resource>
<resource source="GFG" title="Range Update Range Query" url="binary-indexed-tree-range-update-range-queries/"></resource>
</resources>
[My Implementation](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BITrange.h)
### Problems
@ -62,11 +67,19 @@ Binary Indexed Trees can support range increments in addition to range sum queri
<problems-list problems={metadata.problems.lazySegTree} />
## Lazy Segment Tree - Counting Minimums
use segment tree that keeps track of minimum and # of minimums
<problems-list problems={metadata.problems.lazySegCnt} />
## Segment Tree Beats
### Tutorial
- [CF - jiry2](https://codeforces.com/blog/entry/57319)
<resources>
<resource source="CF" title="Intro to Segment Tree Beats" url="blog/entry/57319"></resource>
</resources>
### Problems

View file

@ -65,7 +65,9 @@ Of course, you can do this in $O(\log^2N)$ time with a max segment tree and bina
### Tutorial
- [CF](http://codeforces.com/blog/entry/52854)
<resources>
<resource source="CF" title="Intro to New DS: Wavelet Trees" url="blog/entry/52854"></resource>
</resources>
### Problems

View file

@ -27,8 +27,10 @@ export const metadata = {
## Tutorials
- [zscoder](https://codeforces.com/blog/entry/47821)
- [Kuroni](https://codeforces.com/blog/entry/77298)
<resources>
<resource source="CF" title="zscoder - Slope Trick" url="blog/entry/47821"></resource>
<resource source="CF" title="Kuroni - Slope Trick Explained" url="blog/entry/77298"></resource>
</resources>
From the latter link (modified):

View file

@ -0,0 +1,34 @@
---
id: sweep-line
title: "Sweep Line"
author: Benjamin Qi
description: Introduction to line sweep.
---
## Sweep Line
<resources>
<resource source="CPH" title="30.1, 30.2 - Sweep Line Algorithms"></resource>
</resources>
### Tutorial
- CPH 30
- [TopCoder Line Sweep](https://www.topcoder.com/community/competitive-programming/tutorials/line-sweep-algorithms/)
## Closest Pair
- [Kattis Closest Pair](https://open.kattis.com/problems/closestpair2)
## Line Segment Intersection
- [Cow Steepchase II (Silver)](http://www.usaco.org/index.php?page=viewproblem2&cpid=943)
- :|
## Manhattan MST
https://open.kattis.com/problems/gridmst
CSA 84 The Sprawl
TC 760 ComponentsForever

View file

@ -155,6 +155,7 @@ const ModuleOrdering: {[key: string]: ModuleOrderingItem[]} = {
name: "Geometry",
items: [
"geo-pri",
"sweep-line",
"hull",
"LC",
"lagrange",

View file

@ -39,9 +39,36 @@ export function ResourcesListComponent(props) {
</div>
);
}
const books = {
CPH: '/CPH.pdf',
PAPS: 'https://www.csc.kth.se/~jsannemo/slask/main.pdf',
IUSACO: 'http://darrenyao.com/usacobook/cpp.pdf',
};
const sources = {
TC: 'https://www.topcoder.com/community/competitive-programming/tutorials/',
CPC: 'https://github.com/SuprDewd/T-414-AFLV/tree/master/',
CF: 'http://codeforces.com/',
'cp-algo': 'https://cp-algorithms.com/',
CSA: 'https://csacademy.com/lesson/',
GFG: 'https://www.geeksforgeeks.org/',
};
export function ResourceComponent(props) {
const url = props.source === 'CPH' && !props.url ? '/CPH.pdf' : props.url;
const source = props.source;
let url = props.url;
if (!url) {
if (source in books) {
url = books[source];
} else
throw `No URL. Did you make a typo in the source (${source})? Resource title: ${props.title}`;
}
if (!url.startsWith('http')) {
if (source in sources) {
url = sources[source] + url;
} else
throw `URL ${url} is not valid. Did you make a typo in the source (${source}), or in the URL? Resource name: ${props.title}`;
}
return (
<tr>
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">