FE 0.13.1
Header-only C++ frontend library
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
8namespace 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/// ```
20template<class P, class K>
21class Node {
22public:
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
29private:
30 P* self() { return static_cast<P*>(this); }
31 const P* self() const { return static_cast<const P*>(this); }
32
33public:
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
constexpr Node * aux_parent() noexcept
Definition lct.h:67
constexpr Node() noexcept=default
constexpr Node * find(const D *&k) noexcept
Definition lct.h:40
constexpr bool is_aux_child() const noexcept
Definition lct.h:63
constexpr bool is_descendant_of(Node *other) noexcept
Is this a descendant of other in the aux tree?
Definition lct.h:165
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
constexpr void splay() noexcept
Splays this to the root of its splay tree.
Definition lct.h:82
constexpr P * path_parent() noexcept
Definition lct.h:68
constexpr void link(Node *child) noexcept
Registers the edge this -> child in the aux tree.
Definition lct.h:137
Dir
Index into Node::kids.
Definition lct.h:24
constexpr Dir dir(const Node *kid) const noexcept
Which of Node::kids is kid?
Definition lct.h:76
constexpr P * lca(Node *other) noexcept
Least Common Ancestor of this and other in the aux tree; leaves other exposed.
Definition lct.h:161
bool contains(const K &k) noexcept
Definition lct.h:57
std::array< Node *, 2 > kids
Node::Bot/NodeTop children.
Definition lct.h:177
constexpr Node * expose() noexcept
Definition lct.h:148
Definition lct.h:8