Skip to content

Commit 4b35a25

Browse files
hitonanodeweb-flow
andauthored
Cartesian tree (#124)
* Add cartesian tree * [auto-verifier] verify commit a5ff3e7 Co-authored-by: GitHub <noreply@github.com>
1 parent e1cb4d0 commit 4b35a25

File tree

4 files changed

+70
-0
lines changed

4 files changed

+70
-0
lines changed

.verify-helper/timestamps.remote.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
"string/test/sa_count_keyword.test.cpp": "2021-01-02 01:50:58 +0900",
176176
"string/test/suffix_array.test.cpp": "2021-01-02 00:51:41 +0900",
177177
"string/test/z_algorithm.test.cpp": "2021-01-01 16:52:32 +0900",
178+
"tree/test/cartesian_tree.test.cpp": "2021-10-01 00:13:15 +0900",
178179
"tree/test/diameter.test.cpp": "2021-06-09 00:31:07 +0900",
179180
"tree/test/frequency_table_of_tree_distance.stress.test.cpp": "2021-09-07 01:07:11 +0900",
180181
"tree/test/frequency_table_of_tree_distance.test.cpp": "2021-09-04 01:18:16 +0900",

tree/cartesian_tree.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#pragma once
2+
#include <functional>
3+
#include <vector>
4+
5+
// Cartesian tree
6+
// Complexity: O(n)
7+
// By default, the smaller node is nearer to the root
8+
// Return : -1 (root), parent_idx (otherwise)
9+
// Example: [1, 0, 2] => [1, -1, 1]
10+
// Verified: https://judge.yosupo.jp/problem/cartesian_tree
11+
template <class T, class Cmp = std::less<T>>
12+
std::vector<int> cartesian_tree(const std::vector<T> &X) {
13+
const int n = X.size();
14+
Cmp comp;
15+
std::vector<int> st(n);
16+
int sz = 0;
17+
18+
std::vector<int> par(n, -1);
19+
20+
for (int i = 0; i < n; ++i) {
21+
while (sz >= 2 and comp(X[i], X[st[sz - 1]])) {
22+
par[st[sz - 1]] = comp(X[i], X[st[sz - 2]]) ? st[sz - 2] : i;
23+
--sz;
24+
}
25+
if (sz == 1 and comp(X[i], X[st[sz - 1]])) par[st[--sz]] = i;
26+
st[sz++] = i;
27+
}
28+
for (; sz > 1; --sz) par[st[sz - 1]] = st[sz - 2];
29+
return par;
30+
};

tree/cartesian_tree.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: Cartesian tree
3+
documentation_of: ./cartesian_tree.hpp
4+
---
5+
6+
比較可能な要素の列に対し,Cartesian tree を計算.各要素の親となる要素の番号を持った長さ $N$ の `std::vector<int>` を返す.$O(N)$.デフォルトでは小さい要素がより根に近くなるが,テンプレート引数に `std::greater<T>` を与えてやることで逆転可能.
7+
8+
## 使用方法
9+
10+
```cpp
11+
std::vector<int> A(N);
12+
for (auto &x : Ainv) x = -x;
13+
auto ret = cartesian_tree(A);
14+
auto ret2 = cartesian_tree<int, std::greater<int>>(Ainv);
15+
```
16+
17+
## 問題例
18+
19+
- [Library Checker: Cartesian Tree](https://judge.yosupo.jp/problem/cartesian_tree)
20+
- [Codeforces Round #745 (Div. 1) D. Subsequence](https://codeforces.com/contest/1580/problem/D)

tree/test/cartesian_tree.test.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#define PROBLEM "https://judge.yosupo.jp/problem/cartesian_tree"
2+
#include "../cartesian_tree.hpp"
3+
#include <cassert>
4+
#include <iostream>
5+
using namespace std;
6+
7+
int main() {
8+
cin.tie(nullptr), ios::sync_with_stdio(false);
9+
int N;
10+
cin >> N;
11+
std::vector<int> A(N);
12+
for (auto &x : A) cin >> x;
13+
auto Ainv = A;
14+
for (auto &x : Ainv) x = -x;
15+
auto ret = cartesian_tree(A);
16+
auto ret2 = cartesian_tree<int, std::greater<int>>(Ainv);
17+
assert(ret == ret2);
18+
for (int i = 0; i < N; ++i) cout << (ret[i] < 0 ? i : ret[i]) << (i + 1 == N ? '\n' : ' ');
19+
}

0 commit comments

Comments
 (0)