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

Create spoj-cot.mdx (solution for the problem I added about persisten… #5073

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 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
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
155 changes: 155 additions & 0 deletions solutions/advanced/spoj-cot.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
id: spoj-cot
source: SPOJ
title: Count on a tree
author: Nigar Hajiyeva
---
## Explanation
1Nigar357 marked this conversation as resolved.
Show resolved Hide resolved


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}]
$$



**Note:**
Value compression is used to effectively handle large numbers.

## Implementation
1Nigar357 marked this conversation as resolved.
Show resolved Hide resolved

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

<LanguageSection>
<CPPSection>

```cpp

#include <bits/stdc++.h>
using namespace std;
const int MAX = 2e5 + 10, MAX_NODES = 2e6, LOG = 20;
int L[MAX_NODES + 1], R[MAX_NODES + 1], t[MAX_NODES + 1], roots[MAX + 1],
up[MAX + 1][LOG + 1];
int tin[MAX + 1], tout[MAX + 1], val[MAX + 1];
vector<int> graph[MAX + 1];
int nxt = 1, timer = 0;

int update(int v, int l, int r, int pos) {
int nw = ++nxt;

if (l == r) {
t[nw] = t[v] + 1;
return nw;
}

L[nw] = L[v];
R[nw] = R[v];
int m = (l + r) / 2;

if (pos <= m) {
L[nw] = update(L[v], l, m, pos);
} else {
R[nw] = update(R[v], m + 1, r, pos);
}

t[nw] = t[L[nw]] + t[R[nw]];
return nw;
}

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

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

if (from != 1) {
up[from][0] = p;
} else {
up[from][0] = from;
}

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;
}

bool is_ancestor(int u, int v) { return tin[u] <= tin[v] && tout[u] >= tout[v]; }

int lca(int u, int v) {
if (is_ancestor(u, v)) return u;
if (is_ancestor(v, u)) return v;
for (int i = LOG - 1; i >= 0; i--) {
if (is_ancestor(up[u][i], v)) continue;
u = up[u][i];
}
return up[u][0];
}

int query(int a, int b, int anc, int pr, int l, int r, int k) {
if (l == r) { return l; }
int m = (l + r) / 2;
int cnt = t[L[a]] + t[L[b]] - t[L[anc]] - t[L[pr]];
if (cnt >= k) return query(L[a], L[b], L[anc], L[pr], l, m, k);
else return query(R[a], R[b], R[anc], R[pr], m + 1, r, k - cnt);
}

int main() {
int n, m;
cin >> n >> m;
vector<int> compr;
compr.push_back(-INT_MAX);

for (int i = 1; i <= n; i++) {
1Nigar357 marked this conversation as resolved.
Show resolved Hide resolved
cin >> val[i];
compr.push_back(val[i]);
}

sort(compr.begin(), compr.end());
1Nigar357 marked this conversation as resolved.
Show resolved Hide resolved
compr.resize(unique(compr.begin(), compr.end()) - compr.begin());

for (int i = 1; i <= n; i++) {
val[i] = lower_bound(compr.begin(), compr.end(), val[i]) - compr.begin();
}

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

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

for (int i = 0; i < m; i++) {
int a, b, k;
cin >> a >> b >> k;
int common = lca(a, b);
int pr = (common == 1) ? 0 : up[common][0];
cout << compr[query(roots[a], roots[b], roots[common], roots[pr], 1, MAX, k)]
<< '\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.
Loading