Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

solution for spoj-cot #5073

Open
wants to merge 72 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
fe06370
Create spoj-cot.mdx (solution for the problem I added about persisten…
1Nigar357 Jan 22, 2025
53a37c1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 22, 2025
9a8a775
Update spoj-cot.mdx
1Nigar357 Jan 22, 2025
997b2e1
Update spoj-cot.mdx
TheGamingMousse Jan 22, 2025
daddec5
Update Persistent.problems.json (change the kind in the solution meta…
1Nigar357 Jan 23, 2025
0ddcbd2
Update solutions/advanced/spoj-cot.mdx
1Nigar357 Jan 23, 2025
b872dea
Update spoj-cot.mdx
1Nigar357 Jan 23, 2025
1dc48cf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 23, 2025
0b80073
Update spoj-cot.mdx (Modified the explanation part and organized the …
1Nigar357 Jan 23, 2025
6ffd62c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 23, 2025
3a0ace6
Update spoj-cot.mdx
1Nigar357 Jan 23, 2025
0114d34
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 23, 2025
43ecc8c
Update spoj-cot.mdx
1Nigar357 Jan 23, 2025
9878da2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 23, 2025
74478a6
Update solutions/advanced/spoj-cot.mdx
1Nigar357 Jan 23, 2025
cb7950b
Update solutions/advanced/spoj-cot.mdx
1Nigar357 Jan 23, 2025
ea05116
Update spoj-cot.mdx
1Nigar357 Jan 23, 2025
8933218
Update spoj-cot.mdx
1Nigar357 Jan 24, 2025
5f43b1e
Update spoj-cot.mdx
1Nigar357 Jan 24, 2025
70012c1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 24, 2025
c205dd5
Create example1.png
1Nigar357 Jan 24, 2025
9032de1
Add files via upload
1Nigar357 Jan 24, 2025
46c28cc
Rename Screenshot 2025-01-24 at 1.39.50 AM.png to example.png
1Nigar357 Jan 24, 2025
af2d2e0
Delete solutions/advanced/spoj-cot/example1.png
1Nigar357 Jan 24, 2025
5427b2f
Update spoj-cot.mdx (Added a picture)
1Nigar357 Jan 24, 2025
37d8141
Update spoj-cot.mdx
1Nigar357 Jan 24, 2025
95b3933
Update spoj-cot.mdx (added \texttt)
1Nigar357 Jan 28, 2025
8c6ba59
Update spoj-cot.mdx
1Nigar357 Jan 28, 2025
64139d4
Update spoj-cot.mdx
1Nigar357 Jan 28, 2025
d13cdc7
Update spoj-cot.mdx
1Nigar357 Jan 28, 2025
f700aea
Update spoj-cot.mdx
1Nigar357 Jan 28, 2025
c60fda1
Update spoj-cot.mdx
1Nigar357 Jan 29, 2025
c65e0ea
Update spoj-cot.mdx
1Nigar357 Jan 29, 2025
a956b3b
Update spoj-cot.mdx ("Wrapped the elements of formula inside "\texttt"")
1Nigar357 Jan 29, 2025
34e2eee
Update spoj-cot.mdx (Modified the code)
1Nigar357 Feb 1, 2025
122943a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 1, 2025
336dc27
Update spoj-cot.mdx (Decreased the number of nodes)
1Nigar357 Feb 1, 2025
05e5cf9
Update spoj-cot.mdx (updated the solution code)
1Nigar357 Feb 1, 2025
fdb6e90
Update spoj-cot.mdx
1Nigar357 Feb 10, 2025
cced12a
Update spoj-cot.mdx
1Nigar357 Feb 24, 2025
2454592
Update spoj-cot.mdx (Cleaned up the code added struct)
1Nigar357 Feb 25, 2025
7cab838
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 25, 2025
c77a058
Update spoj-cot.mdx (Added comments and braces for all if statements)
1Nigar357 Feb 28, 2025
1b64a7c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 28, 2025
5bef6e9
Update spoj-cot.mdx
1Nigar357 Feb 28, 2025
5485d44
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 28, 2025
2c8061d
Update spoj-cot.mdx
1Nigar357 Mar 2, 2025
3a465f5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 2, 2025
81defd9
Update spoj-cot.mdx
1Nigar357 Mar 3, 2025
f8279fd
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 3, 2025
a5a3eef
Update spoj-cot.mdx
1Nigar357 Mar 3, 2025
0d44000
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 3, 2025
ce16b84
Update spoj-cot.mdx
1Nigar357 Mar 3, 2025
2bb3ecf
Merge branch 'master' into patch-1
ryanchou-dev Mar 5, 2025
57448d6
Update spoj-cot.mdx
1Nigar357 Mar 5, 2025
32f1361
Update spoj-cot.mdx
1Nigar357 Mar 7, 2025
513239b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 7, 2025
556bed8
Update spoj-cot.mdx
1Nigar357 Mar 8, 2025
c003723
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 8, 2025
24f1358
Update spoj-cot.mdx
1Nigar357 Mar 8, 2025
5377a7b
Update spoj-cot.mdx
1Nigar357 Mar 8, 2025
18193fb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 8, 2025
f3096a5
Update spoj-cot.mdx
1Nigar357 Mar 8, 2025
1419165
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 8, 2025
a3d064f
Update spoj-cot.mdx
1Nigar357 Mar 8, 2025
5506bd6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 8, 2025
cc7e401
Update spoj-cot.mdx
1Nigar357 Mar 9, 2025
5f9ac1d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 9, 2025
1ef8387
Update spoj-cot.mdx
1Nigar357 Mar 9, 2025
0322022
Update spoj-cot.mdx
1Nigar357 Mar 9, 2025
e9a7bac
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 9, 2025
aeacb0b
Update spoj-cot.mdx
1Nigar357 Mar 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/6_Advanced/Persistent.problems.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"isStarred": true,
"tags": ["Persistent Segtree"],
"solutionMetadata": {
"kind": "none"
"kind": "internal"
}
},
{
Expand Down
213 changes: 213 additions & 0 deletions solutions/advanced/spoj-cot.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
---
id: spoj-cot
source: SPOJ
title: Count on a tree
author: Nigar Hajiyeva
---
## Explanation


In this code, a persistent segment tree is built for each node in the tree by creating a new version based on its parent’s segment tree.

First, a persistent segment tree for the root node, which shows the frequency of the values encountered, is built. We set all of the values of this tree to zeros. To incorporate the value of the current node, we create a new version of the segment tree by adding nodes to the parent’s tree and incrementing the segment tree node corresponding to the current node’s value. We store the root node of the new version of the tree for future reference. This way, we don't need to build a completely new tree and modify only the necessary nodes while reusing the unchanged parts.

Each persistent segment tree keeps the frequency of numbers on the way from the root of the tree given in the input to itself. When asked for the kth minimum node in the path of $u$ to $v$, the code first determines the lowest common ancestor (LCA) of the tree in the input using binary lifting. Next, we run a binary search using the frequency values from the persistent segment tree versions of four nodes: $u$, $v$, the LCA, and the parent of the LCA.

Since the values that are not on the path of $u$ and $v$, but on the path from the root node to the nodes $u$ and $v$ are also counted in their persistent segment trees, just considering their persistent segment trees would produce the wrong results.

![example](spoj-cot/example.png)

**Handling Overcounting with LCA**

We subtract the frequencies of nodes from the root node to the LCA and its parent because we count the nodes twice from the root node to the LCA. In addition, since the LCA is on the path of $u$ to $v$, we subtract the frequencies from the LCA and the parent of the LCA to consider the value of the LCA.

$$
\texttt{leftCountFromUToV} = \texttt{leftCount}[\texttt{$u$}]+\texttt{leftCount}[\texttt{$v$}]−\texttt{leftCount}[\texttt{LCA}]−\texttt{leftCount}[\texttt{parentOfLCA}]
$$

This formula tracks the frequencies of values in the left subtree of the persistent segment tree along the path from $u$ to $v$.

<Info>**Note: Value compression is used to effectively handle large numbers.**</Info>

## Implementation

**Time Complexity:** $\mathcal{O}((N+M) \cdot \log{N})$

<LanguageSection>
<CPPSection>

```cpp
#include <bits/stdc++.h>
using namespace std;
int timer = 0;
const int MAX_NODES_GRAPH = 1e5;

struct PersistentSegmentTree {
static const int MAX_NODES_TREE = 2e6;
int left_child[MAX_NODES_TREE + 1], right_child[MAX_NODES_TREE + 1],
frequency[MAX_NODES_TREE + 1];
int nxt = 1;
/*
* Updates the tree at a given position by incrementing the frequency of the
* specific number added. It creates new nodes for every segment along
* the path from the root to the target position, preserving the
* previous version of the tree while modifying only the necessary parts.
*/
int update(int prev_node, int left, int right, int index) {
// Create a new node for the updated tree version
int new_node = ++nxt;

if (left == right) {
// At leaf, increment the value at position 'pos'
frequency[new_node] = frequency[prev_node] + 1;
return new_node;
}
// Copy left child from the previous version
left_child[new_node] = left_child[prev_node];

// Copy right child from the previous version
right_child[new_node] = right_child[prev_node];
int middle = (left + right) / 2;

// Update the left or right child based on the position
if (index <= middle) {
left_child[new_node] = update(left_child[prev_node], left, middle, index);
} else {
right_child[new_node] =
update(right_child[prev_node], middle + 1, right, index);
}

// Update the current node's value by combining the values of its children
frequency[new_node] =
frequency[left_child[new_node]] + frequency[right_child[new_node]];
return new_node;
}

int get_kth_smallest(int a, int b, int anc, int pr, int l, int r, int k) {
// If we've reached a leaf, return the current position
if (l == r) { return l; }

int m = (l + r) / 2;

// Calculate the number of elements in the left child of the current range
int left_subtree_count = frequency[left_child[a]] + frequency[left_child[b]] -
frequency[left_child[anc]] - frequency[left_child[pr]];

if (left_subtree_count >= k) {
return get_kth_smallest(left_child[a], left_child[b], left_child[anc],
left_child[pr], l, m, k);
} else {
return get_kth_smallest(right_child[a], right_child[b], right_child[anc],
right_child[pr], m + 1, r, k - left_subtree_count);
}
}
};

PersistentSegmentTree pst;

struct Tree {
int LOG;
int roots[MAX_NODES_GRAPH + 1], tin[MAX_NODES_GRAPH + 1], tout[MAX_NODES_GRAPH + 1],
val[MAX_NODES_GRAPH + 1];
vector<vector<int>> up;
vector<int> graph[MAX_NODES_GRAPH + 1];

Tree(int n) {
LOG = ceil(log2(n));
up.assign(n + 1, vector<int>(LOG + 1, 0));
}

void dfs(int from, int p) {
int root = roots[p];
root = pst.update(root, 1, MAX_NODES_GRAPH, val[from]);

roots[from] = root;
tin[from] = ++timer;

// Set parent of the node
if (from != 1) {
up[from][0] = p;
} else {
up[from][0] = from;
}

// Precompute ancestors at each level
for (int i = 1; i < LOG; i++) { up[from][i] = up[up[from][i - 1]][i - 1]; }

for (int to : graph[from]) {
if (to == p) continue;
dfs(to, from);
}
tout[from] = timer;
}

// Checks if u is ancestor of v
bool is_ancestor(int u, int v) { return tin[u] <= tin[v] && tout[u] >= tout[v]; }

// Finds the lowest common ancestor (LCA) of u and v
int lca(int u, int v) {
if (is_ancestor(u, v)) { return u; }
if (is_ancestor(v, u)) { return v; }

// Traverse ancestors of 'u' from highest to lowest level
for (int i = LOG - 1; i >= 0; i--) {
// Skip if up[u][i] is an ancestor of v, otherwise update u
if (is_ancestor(up[u][i], v)) { continue; }
u = up[u][i];
}
return up[u][0];
}
};

int main() {
int n, m;
cin >> n >> m;
Tree g(n);

vector<int> compr;
compr.push_back(-INT_MAX);

for (int i = 1; i <= n; i++) {
cin >> g.val[i];
compr.push_back(g.val[i]);
}

// Sort for compression
sort(compr.begin(), compr.end());
compr.resize(unique(compr.begin(), compr.end()) - compr.begin());

// Map original values to compressed values
for (int i = 1; i <= n; i++) {
g.val[i] = lower_bound(compr.begin(), compr.end(), g.val[i]) - compr.begin();
}

// Build the graph
for (int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
g.graph[a].push_back(b);
g.graph[b].push_back(a);
}

g.roots[0] = ++timer;
g.dfs(1, 0);

// Process each query
for (int i = 0; i < m; i++) {
int a, b, k;
cin >> a >> b >> k;
// Find LCA of a and b
int common = g.lca(a, b);

// Find the parent of the common ancestor
int pr = (common == 1) ? 0 : g.up[common][0];

int num = pst.get_kth_smallest(g.roots[a], g.roots[b], g.roots[common],
g.roots[pr], 1, MAX_NODES_GRAPH, k);
cout << compr[num] << '\n';
}
}
```

</CPPSection>
</LanguageSection>
Binary file added solutions/advanced/spoj-cot/example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.