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