FE
0.13.1
Header-only C++ frontend library
Toggle main menu visibility
Loading...
Searching...
No Matches
lct.h
Go to the documentation of this file.
1
#pragma once
2
3
#include <cassert>
4
#include <cstddef>
5
6
#include <array>
7
8
namespace
fe::lct
{
9
10
/// This is an **intrusive** [Link-Cut-Tree](https://en.wikipedia.org/wiki/Link/cut_tree).
11
/// Intrusive means that you have to inherit from this class via
12
/// [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) like this:
13
/// ```
14
/// class Node : public lct::Node<Node, MyKey> {
15
/// constexpr bool lt(const MyKey& key) const noexcept { ... }
16
/// constexpr bool eq(const MyKey& key) const noexcept { ... }
17
/// // ...
18
/// };
19
/// ```
20
template
<
class
P,
class
K>
21
class
Node
{
22
public
:
23
/// Index into Node::kids.
24
enum
Dir
:
size_t
{
25
Bot
,
///< left/deeper/bottom/leaf-direction
26
Top
,
///< right/shallower/top/root-direction
27
};
28
29
private
:
30
P* self() {
return
static_cast<
P*
>
(
this
); }
31
const
P* self()
const
{
return
static_cast<
const
P*
>
(
this
); }
32
33
public
:
34
constexpr
Node
() noexcept = default;
35
36
///@name Getters
37
///@{
38
39
/// Find @p k or the element just greater than @p k.
40
constexpr P*
find
(const K& k) noexcept {
41
expose
();
42
auto
prev =
this
;
43
for
(
auto
n =
this
; n;) {
44
if
(n->self()->eq(k))
return
n->splay(), n->self();
45
46
if
(n->self()->lt(k)) {
47
n = n->kids[
Bot
];
48
}
else
{
49
prev = n;
50
n = n->kids[
Top
];
51
}
52
}
53
54
return
prev->self();
55
}
56
57
[[nodiscard]]
bool
contains
(
const
K& k)
noexcept
{
return
find
(k)->eq(k); }
58
///@}
59
60
///@name parent
61
///@{
62
/// Is `this` a child of Node::parent within the same splay tree?
63
constexpr
bool
is_aux_child
() const noexcept {
64
return
parent
&& (
parent
->
kids
[
Bot
] ==
this
||
parent
->
kids
[
Top
] ==
this
);
65
}
66
// clang-format off
67
constexpr
Node
*
aux_parent
() noexcept {
return
is_aux_child
() ?
parent
:
nullptr
; }
68
constexpr
P*
path_parent
() noexcept {
return
!
is_aux_child
() &&
parent
?
parent
->self() :
nullptr
; }
69
// clang-format on
70
///@}
71
72
///@name Splay Tree
73
///@{
74
75
/// Which of Node::kids is @p kid?
76
constexpr
Dir
dir
(
const
Node
* kid)
const
noexcept
{
77
assert(
kids
[
Bot
] == kid ||
kids
[
Top
] == kid);
78
return
kids
[
Top
] == kid ?
Top
:
Bot
;
79
}
80
81
/// [Splays](https://hackmd.io/@CharlieChuang/By-UlEPFS#Operation1) `this` to the root of its splay tree.
82
constexpr
void
splay
() noexcept {
83
while
(
auto
p =
aux_parent
()) {
84
auto
i = p->dir(
this
);
85
if
(
auto
pp = p->aux_parent()) {
86
auto
j = pp->dir(p);
87
if
(i == j)
// zig-zig/zag-zag
88
pp->rotate(j), p->rotate(i);
89
else
// zig-zag/zag-zig
90
p->rotate(i), pp->rotate(j);
91
}
else
{
// zig/zag
92
p->rotate(i);
93
}
94
}
95
}
96
97
/// Helper for Splay-Tree: rotates `this`'s @p i%th kid `c` into `this`'s (`x`'s) place:
98
/// ```
99
/// | i == Top | i == Bot |
100
/// |-----------------------|------------------------|
101
/// | p p | p p |
102
/// | | | | | | |
103
/// | x c | x c |
104
/// | / \ -> / \ | / \ -> / \ |
105
/// | a c x d | c a d x |
106
/// | / \ / \ | / \ / \ |
107
/// | b d a b | d b b a |
108
/// ```
109
constexpr
void
rotate
(
Dir
i)
noexcept
{
110
auto
j = i ==
Bot
?
Top
:
Bot
;
111
auto
x =
this
;
112
auto
p = x->parent;
113
auto
c = x->kids[i];
114
auto
b = c->kids[j];
115
116
if
(b) b->parent = x;
117
118
// if p is only a path parent, it has no kid to fix up
119
if
(p) {
120
if
(p->kids[
Bot
] == x)
121
p->kids[
Bot
] = c;
122
else
if
(p->kids[
Top
] == x)
123
p->kids[
Top
] = c;
124
}
125
126
x->parent = c;
127
c->parent = p;
128
x->kids[i] = b;
129
c->kids[j] = x;
130
}
131
///@}
132
133
/// @name Link-Cut-Tree
134
///@{
135
136
/// Registers the edge `this -> child` in the *aux* tree.
137
constexpr
void
link
(
Node
* child)
noexcept
{
138
this->
expose
();
139
child->expose();
140
if
(!child->kids[
Top
]) {
141
this->
parent
= child;
142
child->
kids
[
Top
] =
this
;
143
}
144
}
145
146
/// Make a preferred path from `this` to root while putting `this` at the root of the *aux* tree.
147
/// @returns the last valid path_parent().
148
constexpr
P*
expose
() noexcept {
149
Node
* prev =
nullptr
;
150
for
(
auto
curr =
this
; curr; prev = curr, curr = curr->
parent
) {
151
curr->splay();
152
assert(!prev || prev->
parent
== curr);
153
curr->kids[
Bot
] = prev;
154
}
155
splay
();
156
return
prev->self();
157
}
158
159
/// Least Common Ancestor of `this` and @p other in the *aux* tree; leaves @p other expose%d.
160
/// @returns `nullptr`, if @p a and @p b are in different trees.
161
constexpr
P*
lca
(
Node
* other)
noexcept
{
return
this->
expose
(), other->expose(); }
162
163
/// Is `this` a descendant of `other` in the *aux* tree?
164
/// Also `true`, if `this == other`.
165
constexpr
bool
is_descendant_of
(
Node
* other)
noexcept
{
166
if
(
this
== other)
return
true
;
167
this->
expose
();
168
other->splay();
169
auto
curr =
this
;
170
while
(
auto
p = curr->aux_parent())
171
curr = p;
172
return
curr == other;
173
}
174
///@}
175
176
Node
*
parent
=
nullptr
;
///< parent or path-parent
177
std::array<Node*, 2>
kids
= {};
///< Node::Bot/Node::Top children
178
};
179
180
}
// namespace fe::lct
fe::lct::Node::aux_parent
constexpr Node * aux_parent() noexcept
Definition
lct.h:67
fe::lct::Node::Node
constexpr Node() noexcept=default
fe::lct::Node< Node, D * >::find
constexpr Node * find(const D *&k) noexcept
Definition
lct.h:40
fe::lct::Node< Node, D * >::parent
Node * parent
Definition
lct.h:176
fe::lct::Node::is_aux_child
constexpr bool is_aux_child() const noexcept
Definition
lct.h:63
fe::lct::Node::is_descendant_of
constexpr bool is_descendant_of(Node *other) noexcept
Is this a descendant of other in the aux tree?
Definition
lct.h:165
fe::lct::Node::rotate
constexpr void rotate(Dir i) noexcept
Helper for Splay-Tree: rotates this's ith kid c into this's (x's) place:
Definition
lct.h:109
fe::lct::Node::splay
constexpr void splay() noexcept
Splays this to the root of its splay tree.
Definition
lct.h:82
fe::lct::Node::path_parent
constexpr P * path_parent() noexcept
Definition
lct.h:68
fe::lct::Node::link
constexpr void link(Node *child) noexcept
Registers the edge this -> child in the aux tree.
Definition
lct.h:137
fe::lct::Node::Dir
Dir
Index into Node::kids.
Definition
lct.h:24
fe::lct::Node< Node, D * >::Top
@ Top
Definition
lct.h:26
fe::lct::Node< Node, D * >::Bot
@ Bot
Definition
lct.h:25
fe::lct::Node::dir
constexpr Dir dir(const Node *kid) const noexcept
Which of Node::kids is kid?
Definition
lct.h:76
fe::lct::Node::lca
constexpr P * lca(Node *other) noexcept
Least Common Ancestor of this and other in the aux tree; leaves other exposed.
Definition
lct.h:161
fe::lct::Node::contains
bool contains(const K &k) noexcept
Definition
lct.h:57
fe::lct::Node::kids
std::array< Node *, 2 > kids
Node::Bot/NodeTop children.
Definition
lct.h:177
fe::lct::Node< Node, D * >::expose
constexpr Node * expose() noexcept
Definition
lct.h:148
fe::lct
Definition
lct.h:8
fe
lct.h
Generated by
1.18.0