From 5648f2252f6e0d88c93d5e266c910c02e19596e3 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Fri, 15 Jul 2022 07:27:47 +0800 Subject: [PATCH] =?UTF-8?q?#104.=20=E6=99=AE=E9=80=9A=E5=B9=B3=E8=A1=A1?= =?UTF-8?q?=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://loj.ac/s/1515123 --- LibreOJ/104/104.cpp | 418 ++++++++++++++++++++------------------------ 1 file changed, 193 insertions(+), 225 deletions(-) diff --git a/LibreOJ/104/104.cpp b/LibreOJ/104/104.cpp index d2722e79..82d578d9 100644 --- a/LibreOJ/104/104.cpp +++ b/LibreOJ/104/104.cpp @@ -5,274 +5,261 @@ using std::cin; using std::cout; const char endl = '\n'; -template +const int N = 1e5 + 5; + class Splay { private: + size_t root, cnt; + struct node { - T value; - node *lchild, *rchild, *parent, **root; - std::size_t size, count; + size_t l, r, f, c, s; + int v; node() - : value(0), lchild(nullptr), rchild(nullptr), parent(nullptr), root(nullptr), size(0), count(0) {} + : l(0), r(0), f(0), c(0), s(0), v(0) {} - node(const T &_value, node *_parent, node **_root) - : value(_value), lchild(nullptr), rchild(nullptr), parent(_parent), root(_root), size(1), count(1) {} + node(int _v, int _f) + : l(0), r(0), f(_f), c(1), s(1), v(_v) {} - ~node() { - if (lchild != nullptr) delete lchild; - if (rchild != nullptr) delete rchild; + size_t &child(unsigned x) { + return !x ? l : r; } + } tr[N]; - node *&child(unsigned int x) { - return !x ? lchild : rchild; + // 上传信息 + void pushup(size_t u) { + tr[u].s = tr[tr[u].l].s + tr[tr[u].r].s + tr[u].c; + } + + unsigned relation(size_t u) { + // 如果当前节点是其父亲节点的左儿子则返回 0,否则返回 1 + return u == tr[tr[u].f].l ? 0 : 1; + } + + void rotate(size_t u) { + // 旧的父节点 + size_t p = tr[u].f; + + // 当前节点与父节点之间的关系 + unsigned x = relation(u); + + // 当前节点 <-> 父节点的父节点 + if (tr[p].f) { + tr[tr[p].f].child(relation(p)) = u; } + tr[u].f = tr[p].f; - unsigned int relation() const { - // 如果当前节点是其父亲节点的左儿子则返回 0,否则返回 1 - return this == parent->lchild ? 0 : 1; + // 原先的另一个子节点 <-> 父节点 + if (tr[u].child(x ^ 1)) { + tr[tr[u].child(x ^ 1)].f = p; } + tr[p].child(x) = tr[u].child(x ^ 1); - // 左儿子大小 - std::size_t lsize() const { - return lchild == nullptr ? 0 : lchild->size; - } + // 原先的父节点 -> 子节点 + tr[u].child(x ^ 1) = p; + tr[p].f = u; - // 右儿子大小 - std::size_t rsize() const { - return rchild == nullptr ? 0 : rchild->size; - } + // 更新节点信息 + pushup(p); + pushup(u); + } - // 上传信息 - void pushup() { - size = lsize() + count + rsize(); - } - - // 旋转 - void rotate() { - node *old = parent; - unsigned int x = relation(); - - if (old->parent != nullptr) { - old->parent->child(old->relation()) = this; - } - parent = old->parent; - - old->child(x) = child(x ^ 1); - if (child(x ^ 1) != nullptr) { - child(x ^ 1)->parent = old; - } - - child(x ^ 1) = old; - old->parent = this; - - old->pushup(); - pushup(); - - if (parent == nullptr) *root = this; - } - - // Splay - void splay(node *target = nullptr) { - while (parent != target) { - if (parent->parent == target) { // 父节点是目标节点 - rotate(); - } else if (relation() == parent->relation()) { // 关系相同 - parent->rotate(); - rotate(); - } else { - rotate(); - rotate(); - } - } - } - - // 前驱:左子树的最右点 - node *predecessor() { - node *pred = lchild; - - while (pred->rchild != nullptr) { - pred = pred->rchild; - } - - return pred; - } - - // 后继:右子树的最左点 - node *successor() { - node *succ = rchild; - - while (succ->lchild != nullptr) { - succ = succ->lchild; - } - - return succ; - } - } * root; - - // 插入(内部函数) - node *_insert(const T &value) { - node **target = &root, *parent = nullptr; - - while (*target != nullptr && (*target)->value != value) { - parent = *target; - parent->size++; - - // 根据大小向左右子树迭代 - if (value < parent->value) { - target = &parent->lchild; + // Splay + // + // 旋转到给定的位置(target),默认行为为旋转为根节点 + void splay(size_t u, size_t t = 0) { + while (tr[u].f != t) { + if (tr[tr[u].f].f == t) { + rotate(u); + } else if (relation(u) == relation(tr[u].f)) { + rotate(tr[u].f); + rotate(u); } else { - target = &parent->rchild; + rotate(u); + rotate(u); } } - if (*target == nullptr) { - *target = new node(value, parent, &root); - } else { - (*target)->count++; - (*target)->size++; + // 更新根节点 + if (!t) root = u; + } + + // 前驱 + // + // 左子树的最右点 + size_t _predecessor(size_t u) { + size_t cur = tr[u].l; + + while (tr[cur].r) { + cur = tr[cur].r; } - (*target)->splay(); + return cur; + } + + // 后继 + // + // 右子树的最左点 + size_t _successor(size_t u) { + size_t cur = tr[u].r; + + while (tr[cur].l) { + cur = tr[cur].l; + } + + return cur; + } + + size_t _find(const int &v) { + size_t u = root; + + while (u && tr[u].v != v) { + // 根据数值大小向左右子树迭代 + u = v < tr[u].v ? tr[u].l : tr[u].r; + } + + if (u) splay(u); + + return u; + } + + size_t _insert(const int &v) { + size_t u = root, f = 0; + + while (u && tr[u].v != v) { + f = u; + // 根据数值大小向左右子树迭代 + u = v < tr[u].v ? tr[u].l : tr[u].r; + } + + if (u) { + tr[u].c++; + tr[u].s++; + } else { + tr[u = ++cnt] = node(v, f); + if (f) tr[f].child(v > tr[f].v) = u; + } + + splay(u); return root; } - // 查找指定的值对应的节点 - node *find(const T &value) { - node *node = root; // 从根节点开始查找 + void _erase(size_t u) { + if (!u) return; - while (node != nullptr && value != node->value) { - if (value < node->value) { - node = node->lchild; - } else { - node = node->rchild; - } - } - - if (node != nullptr) { - node->splay(); - } - - return node; - } - - // 删除 - void erase(node *u) { - if (u == nullptr) return; - - if (u->count > 1) { // 存在重复的数 - u->splay(); - u->count--; - u->size--; + if (tr[u].c > 1) { // 存在重复的数 + splay(u); + tr[u].c--; + tr[u].s--; return; } - node *pred = u->predecessor(), - *succ = u->successor(); + size_t pred = _predecessor(u), + succ = _successor(u); - pred->splay(); - succ->splay(pred); + splay(pred); // 将前驱旋转到根节点 + splay(succ, pred); // 将后继旋转到根节点的右儿子 - delete succ->lchild; - succ->lchild = nullptr; + tr[succ].l = 0; // 此时要删的节点为根节点的左儿子且为叶子节点 - succ->pushup(); - pred->pushup(); + // 更新节点信息 + pushup(succ); + pushup(pred); } public: Splay() - : root(nullptr) { - insert(std::numeric_limits::min()); - insert(std::numeric_limits::max()); - } - - ~Splay() { - delete root; + : root(0), cnt(0) { + // 插入哨兵节点 + insert(std::numeric_limits::min()); + insert(std::numeric_limits::max()); } // 插入 - void insert(const T &value) { - _insert(value); + void insert(const int &v) { + _insert(v); } // 删除 - void erase(const T &value) { - node *node = find(value); - - if (node == nullptr) return; - - erase(node); + void erase(const int &v) { + _erase(_find(v)); } // 排名 - unsigned int rank(const T &value) { - node *node = find(value); + unsigned rank(const int &v) { + size_t u = _find(v); - if (node == nullptr) { - node = _insert(value); - // 此时 node 已经成为根节点,直接计算即可 - int res = node->lsize(); // 由于「哨兵」的存在,此处无需 -1 - erase(node); + if (!u) { // 不存在则插入一个方便查找 + u = _insert(v); - return res; + // 此时 u 已经成为根节点,直接取左子树大小即可 + unsigned r = tr[tr[u].l].s; + + _erase(u); + + return r; } - // 此时 node 已经成为根节点,直接计算即可 - return node->lsize(); + return tr[tr[u].l].s; } // 选择 - const T &select(int k) { - node *node = root; + const int &select(unsigned k) { + size_t u = root; - while (k < node->lsize() || k >= node->lsize() + node->count) { - if (k < node->lsize()) { // 所需的节点在左子树中 - node = node->lchild; + while (k < tr[tr[u].l].s || k >= tr[tr[u].l].s + tr[u].c) { + if (k < tr[tr[u].l].s) { + u = tr[u].l; } else { - k -= node->lsize() + node->count; - node = node->rchild; + k -= tr[tr[u].l].s + tr[u].c; + u = tr[u].r; } } - node->splay(); + splay(u); - return node->value; + return tr[u].v; } // 前驱 - const T &predecessor(const T &value) { - node *node = find(value); + const int &predecessor(const int &v) { + size_t u = _find(v); - if (node == nullptr) { - node = _insert(value); - const T &result = node->predecessor()->value; - erase(node); - return result; + if (!u) { // 不存在则插入一个方便查找 + u = _insert(v); + + const int &r = tr[_predecessor(u)].v; + + _erase(u); // 删除 + + return r; } - return node->predecessor()->value; + return tr[_predecessor(u)].v; } // 后继 - const T &successor(const T &value) { - node *node = find(value); + const int &successor(const int &v) { + size_t u = _find(v); - if (node == nullptr) { - node = _insert(value); - const T &result = node->successor()->value; - erase(node); - return result; + if (!u) { // 不存在则插入一个方便查找 + u = _insert(v); + + const int &r = tr[_successor(u)].v; + + _erase(u); // 删除 + + return r; } - return node->successor()->value; + return tr[_successor(u)].v; } }; int n; -Splay tree; +Splay tree; int main() { std::ios::sync_with_stdio(false); @@ -280,42 +267,23 @@ int main() { cin >> n; - for (int i = 1; i <= n; i++) { + while (n--) { int op, x; cin >> op >> x; - switch (op) { - case 1: { - tree.insert(x); - - break; - } - case 2: { - tree.erase(x); - - break; - } - case 3: { - cout << tree.rank(x) << endl; - - break; - } - case 4: { - cout << tree.select(x) << endl; - - break; - } - case 5: { - cout << tree.predecessor(x) << endl; - - break; - } - case 6: { - cout << tree.successor(x) << endl; - - break; - } + if (op == 1) { + tree.insert(x); + } else if (op == 2) { + tree.erase(x); + } else if (op == 3) { + cout << tree.rank(x) << endl; + } else if (op == 4) { + cout << tree.select(x) << endl; + } else if (op == 5) { + cout << tree.predecessor(x) << endl; + } else { // op == 6 + cout << tree.successor(x) << endl; } }