Skip to content

Commit 1c31a99

Browse files
committed
add permutation tree test
1 parent dde7f2e commit 1c31a99

File tree

3 files changed

+52
-22
lines changed

3 files changed

+52
-22
lines changed

other_algorithms/permutation_tree.hpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
// Permutation tree
1010
// Complexity: O(N log N)
11-
// https://codeforces.com/blog/entry/78898 https://yukicoder.me/problems/no/1720
11+
// https://codeforces.com/blog/entry/78898 https://judge.yosupo.jp/problem/common_interval_decomposition_tree
1212
struct permutation_tree {
1313
enum NodeType {
1414
JoinAsc,
@@ -17,13 +17,14 @@ struct permutation_tree {
1717
Leaf,
1818
None,
1919
};
20-
struct node {
20+
struct Node {
2121
NodeType tp;
2222
int L, R; // i in [L, R)
2323
int mini, maxi; // A[i] in [mini, maxi]
24+
int par_id = -1;
2425
std::vector<int> child;
2526
int sz() const { return R - L; }
26-
template <class OStream> friend OStream &operator<<(OStream &os, const node &n) {
27+
template <class OStream> friend OStream &operator<<(OStream &os, const Node &n) {
2728
os << "[[" << n.L << ',' << n.R << ")(ch:";
2829
for (auto i : n.child) os << i << ',';
2930
return os << ")(tp=" << n.tp << ")]";
@@ -32,14 +33,14 @@ struct permutation_tree {
3233

3334
int root;
3435
std::vector<int> A;
35-
std::vector<node> nodes;
36+
std::vector<Node> nodes;
3637

37-
void _add_child(int parid, int chid) {
38-
nodes[parid].child.push_back(chid);
39-
nodes[parid].L = std::min(nodes[parid].L, nodes[chid].L);
40-
nodes[parid].R = std::max(nodes[parid].R, nodes[chid].R);
41-
nodes[parid].mini = std::min(nodes[parid].mini, nodes[chid].mini);
42-
nodes[parid].maxi = std::max(nodes[parid].maxi, nodes[chid].maxi);
38+
void _add_child(int par_id, int chid) {
39+
nodes[par_id].child.push_back(chid);
40+
nodes[par_id].L = std::min(nodes[par_id].L, nodes[chid].L);
41+
nodes[par_id].R = std::max(nodes[par_id].R, nodes[chid].R);
42+
nodes[par_id].mini = std::min(nodes[par_id].mini, nodes[chid].mini);
43+
nodes[par_id].maxi = std::max(nodes[par_id].maxi, nodes[chid].maxi);
4344
}
4445

4546
permutation_tree() : root(-1) {}
@@ -62,15 +63,15 @@ struct permutation_tree {
6263
lo.push_back(i);
6364

6465
int h = nodes.size();
65-
nodes.push_back({NodeType::Leaf, i, i + 1, A[i], A[i], std::vector<int>{}});
66+
nodes.push_back({NodeType::Leaf, i, i + 1, A[i], A[i], -1, std::vector<int>{}});
6667

6768
while (true) {
6869
NodeType join_tp = NodeType::None;
6970
if (!st.empty() and nodes[st.back()].maxi + 1 == nodes[h].mini) join_tp = JoinAsc;
7071
if (!st.empty() and nodes[h].maxi + 1 == nodes[st.back()].mini) join_tp = JoinDesc;
7172

7273
if (!st.empty() and join_tp != NodeType::None) {
73-
const node &vtp = nodes[st.back()];
74+
const Node &vtp = nodes[st.back()];
7475
// Insert v as the child of the top node in the stack
7576
if (join_tp == vtp.tp) {
7677
// Append child to existing Join node
@@ -81,15 +82,15 @@ struct permutation_tree {
8182
// Make new join node (with exactly two children)
8283
int j = st.back();
8384
nodes.push_back(
84-
{join_tp, nodes[j].L, nodes[j].R, nodes[j].mini, nodes[j].maxi, {j}});
85+
{join_tp, nodes[j].L, nodes[j].R, nodes[j].mini, nodes[j].maxi, -1, {j}});
8586
st.pop_back();
8687
_add_child(nodes.size() - 1, h);
8788
h = nodes.size() - 1;
8889
}
8990
} else if (seg.prod(0, i + 1 - nodes[h].sz()) == 0) {
9091
// Make Cut node
9192
int L = nodes[h].L, R = nodes[h].R, maxi = nodes[h].maxi, mini = nodes[h].mini;
92-
nodes.push_back({NodeType::Cut, L, R, mini, maxi, {h}});
93+
nodes.push_back({NodeType::Cut, L, R, mini, maxi, -1, {h}});
9394
h = nodes.size() - 1;
9495
do {
9596
_add_child(h, st.back());
@@ -104,6 +105,11 @@ struct permutation_tree {
104105
seg.add(0, i + 1, -1);
105106
}
106107
assert(st.size() == 1);
108+
109+
for (int i = 0; i < int(nodes.size()); i++) {
110+
for (auto ch : nodes[i].child) nodes[ch].par_id = i;
111+
}
112+
107113
root = st[0];
108114
}
109115

other_algorithms/permutation_tree.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
---
2-
title: Permutation tree (順列木)
2+
title: Common interval decomposition tree / "Permutation tree" (順列木)
33
documentation_of: ./permutation_tree.hpp
44
---
55

6-
与えられた $[0, \dots, N - 1]$ の置換 $\mathbf{A} = [A\_0, \dots, A\_{N - 1}]$ について,この連続部分列であってその長さがそれに含まれる要素の最大値と最小値の差に $1$ を加えた値と等しくなるようなものを全て列挙するのに役立つデータ構造
6+
順列 $(0, \dots, N - 1)$ の置換 $P = (P\_0, \dots, P\_{N - 1})$ について,この連続部分列であってその区間をソートすると連番となるようなもの(たとえば、 $P = (1, 5, 3, 4, 7, 2, 6)$ における $(5, 3, 4)$ などの部分)を全列挙するのに役立つデータ構造
77

8-
Permutation tree は区間のマージ過程を表す木として表現される.$N$ 個の葉は長さ $1$ の区間(単一の要素)に対応し,根は $\mathbf{A}$ 全体に対応する.
8+
Permutation tree は区間のマージ過程を表す木として表現される.$N$ 個の葉は長さ $1$ の区間(単一の要素)に対応し,根は $P$ 全体に対応する.
99

1010
葉以外の全ての頂点は `Join``Cut` いずれかの属性を持つ.`Join` 属性を持つ頂点は,その子を $c\_1, \dots, c\_k$ とおくと,任意の $1 \le i \le j \le k$ について頂点 $(c\_i, \dots, c\_j)$ が表す区間の和集合は上記の条件を満たす.また,全ての頂点について,その頂点が表す区間全体は上記の条件を満たす.そして,上記の条件を満たす区間はこれらに限られるというのが最も重要な性質である.
1111

12-
1312
## 使用方法(例)
1413

1514
木の各頂点の情報はメンバ変数 `std::vector<node> nodes` に格納されている.特に根が格納されている位置を示す変数が `tree.root`
1615

1716
```cpp
1817
enum NodeType {
19-
JoinAsc, // Join,特に A[i] の値が増加していく
20-
JoinDesc, // Join,特に A[i] の値が減少していく
18+
JoinAsc, // Join,特に P[i] の値が増加していく
19+
JoinDesc, // Join,特に P[i] の値が減少していく
2120
Cut, // Cut
2221
Leaf, // 葉である
2322
None,
2423
};
2524
struct node {
2625
NodeType tp;
2726
int L, R; // [L, R) : 頂点が表す区間
28-
int mini, maxi; // 区間に含まれる A[i] (L <= i < R) の最小・最大値
27+
int mini, maxi; // 区間に含まれる P[i] (L <= i < R) の最小・最大値
2928
std::vector<int> child; // 子の頂点番号(昇順)
3029
};
3130
```
@@ -39,7 +38,7 @@ struct node {
3938
上記の条件を満たす区間の個数だけを求めればよい問題.
4039
4140
```cpp
42-
permutation_tree tree(A);
41+
permutation_tree tree(P);
4342
4443
auto rec = [&](auto &&self, int now) -> long long {
4544
long long ret = 1;
@@ -84,6 +83,8 @@ rec(rec, tree.root);
8483
for (int i = 1; i <= K; i++) cout << dp[i][N].val() << '\n';
8584
```
8685
86+
### [Common Interval Decomposition Tree](https://judge.yosupo.jp/problem/common_interval_decomposition_tree)
87+
8788
## リンク
8889
8990
1. [Tutorial on Permutation Tree (析合树) - Codeforces](https://codeforces.com/blog/entry/78898)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#define PROBLEM "https://judge.yosupo.jp/problem/common_interval_decomposition_tree"
2+
#include "../permutation_tree.hpp"
3+
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+
12+
vector<int> P(N);
13+
for (auto &p : P) cin >> p;
14+
15+
const permutation_tree pt(P);
16+
17+
cout << pt.nodes.size() << '\n';
18+
19+
for (const auto &node : pt.nodes) {
20+
cout << node.par_id << ' ' << node.L << ' ' << node.R - 1 << ' '
21+
<< (node.tp == permutation_tree::Cut ? "prime" : "linear") << '\n';
22+
}
23+
}

0 commit comments

Comments
 (0)