lookup, insert, erase などの操作をならし計算量 O(logn) で実現する平衡二分探索木([Sleator, Tarjan '83]).
動的連結性クエリに高速に答える手法(Link Cut Tree)を考案する過程で得られたデータ構造.
以下では遅延処理(区間加算, 区間総和)を施した実装にしている.
時間計算量: 各クエリ O(logn) (ならし計算量)
- template<typename _Key, typename _Tp> class node {
- public:
- int sz;
- _Key key;
- _Tp val, al, lazy;
- node *left, *right, *par;
- node(_Key _key, _Tp _val) noexcept : sz(1), key(_key), val(_val), al(val), lazy(id1),
- left(nullptr), right(nullptr), par(nullptr){}
- static const _Tp id1 = (_Tp)0;
- static const _Tp id2 = (_Tp)0;
- static void opr1(_Tp& arg1, const _Tp arg2){ arg1 += arg2; }
- static _Tp opr2(const _Tp arg1, const _Tp arg2){ return arg1 + arg2; }
- inline bool isRoot() const { return !par; }
- void push(){
- if(lazy != id1){
- opr1(val, lazy), al += lazy * sz;
- if(left) opr1(left->lazy, lazy);
- if(right) opr1(right->lazy, lazy);
- lazy = id1;
- }
- }
- void eval(){
- sz = 1, al = val;
- if(left) left->push(), sz += left->sz, al = opr2(left->al, al);
- if(right) right->push(), sz += right->sz, al = opr2(al, right->al);
- }
- void rotate(bool right_){
- node<_Key, _Tp> *p = par, *g = p->par;
- if(right_){
- if((p->left = right)) right->par = p;
- right = p, p->par = this;
- }else{
- if((p->right = left)) left->par = p;
- left = p, p->par = this;
- }
- p->eval(), eval();
- if(!(par = g)) return;
- if(g->left == p) g->left = this;
- if(g->right == p) g->right = this;
- g->eval();
- }
- };
- template<typename _Key, typename _Tp>
- int size(node<_Key, _Tp>* u){ return u ? u->sz : 0; }
- // 頂点 u を木の根にする
- template<typename _Key, typename _Tp>
- node<_Key, _Tp>* splay(node<_Key, _Tp>* u) noexcept {
- if(!u) return nullptr;
- while(!(u->isRoot())){
- node<_Key, _Tp> *p = u->par, *gp = p->par;
- if(p->isRoot()){ // zig
- p->push(), u->push();
- u->rotate((u == p->left));
- }else{
- gp->push(), p->push(), u->push();
- bool flag = (u == p->left);
- if((u == p->left) == (p == gp->left)){ // zig-zig
- p->rotate(flag), u->rotate(flag);
- }else{ // zig-zag
- u->rotate(flag), u->rotate(!flag);
- }
- }
- }
- u->push();
- return u;
- }
- // root を根とする木の頂点で k 番目に小さいキー値のものを探索する
- // 返り値は (木の根, k 番目が存在するかしないか(0/1))
- template<typename _Key, typename _Tp>
- pair<node<_Key, _Tp>*, bool> get(const int k, node<_Key, _Tp>* root) noexcept {
- if(size(root) < k) return make_pair(root, false);
- int sum = 0;
- node<_Key, _Tp> *cur = nullptr, *nx = root;
- while(nx){
- cur = nx, cur->push();
- if(size(cur->left) < sum - 1){
- nx = cur->right, sum -= size(cur->left) + 1;
- }else if(size(cur->left) >= sum){
- nx = cur->left;
- }else{
- return make_pair(splay(cur), true);
- }
- }
- }
- // root を根とする木の頂点でキーが _key であるものを探索する
- // 返り値は (木の根, 存在するかしないか(0/1))
- template<typename _Key, typename _Tp>
- pair<node<_Key, _Tp>*, bool> find(const _Key _key, node<_Key, _Tp>* root) noexcept {
- node<_Key, _Tp> *cur = nullptr, *nx = root;
- while(nx){
- cur = nx, cur->push();
- if(cur->key == _key) return make_pair(splay(cur), true);
- if(cur->key > _key) nx = cur->left;
- else nx = cur->right;
- }
- return make_pair(splay(cur), false);
- }
- // root を根とする木の頂点でキーが _key 以上で最小のものを返す(bool は _key 以上のものがあるかないか)
- // _key 以上のものがなくても返り値のノードは nullptr とは限らないことに注意(_key 以上がなくても木の根は変わるので)
- template<typename _Key, typename _Tp>
- pair<node<_Key, _Tp>*, bool> lower_bound(const _Key _key, node<_Key, _Tp>* root) noexcept {
- node<_Key, _Tp> *cur = nullptr, *nx = root, *res = nullptr;
- while(nx){
- cur = nx, cur->push();
- if(cur->key >= _key){
- nx = cur->left;
- if(!res || cur->key <= res->key) res = cur;
- }else nx = cur->right;
- }
- node<_Key, _Tp>* tmp = splay(cur);
- return res ? make_pair(splay(res), true) : make_pair(tmp, false);
- }
- // root を根とする木の頂点でキーが _key を超える最小のものを返す(bool は _key を超えるものがあるかないか)
- // _key を超えるものがなくても返り値のノードは nullptr とは限らないことに注意(_key を超えるものがなくても木の根は変わるので)
- template<typename _Key, typename _Tp>
- pair<node<_Key, _Tp>*, bool> upper_bound(const _Key _key, node<_Key, _Tp>* root) noexcept {
- node<_Key, _Tp> *cur = nullptr, *nx = root, *res = nullptr;
- while(nx){
- cur = nx, cur->push();
- if(cur->key > _key){
- nx = cur->left;
- if(!res || cur->key <= res->key) res = cur;
- }else nx = cur->right;
- }
- node<_Key, _Tp>* tmp = splay(cur);
- return res ? make_pair(splay(res), true) : make_pair(tmp, false);
- }
- // root1 を根とする木のすべての要素が root 2 を根とする木のすべての要素より小さいときの merge
- template<typename _Key, typename _Tp>
- node<_Key, _Tp>* join(node<_Key, _Tp>* root1, node<_Key, _Tp>* root2) noexcept {
- if(!root1 || !root2) return root1 ? root1 : root2;
- node<_Key, _Tp> *cur = nullptr, *nx = root1;
- while(nx) cur = nx, cur->push(), nx = cur->right;
- node<_Key, _Tp>* ver = splay(cur);
- ver->right = root2, ver->eval(), root2->par = ver;
- return ver;
- }
- // root を根とする木に ver を insert する
- template<typename _Key, typename _Tp>
- node<_Key, _Tp>* insert(node<_Key, _Tp>* ver, node<_Key, _Tp>* root) noexcept {
- if(!root) return ver;
- node<_Key, _Tp> *cur = nullptr, *nx = root;
- while(nx){
- cur = nx, cur->push();
- if(cur->key > ver->key) nx = cur->left;
- else nx = cur->right;
- }
- if(cur->key > ver->key) cur->left = ver, ver->par = cur;
- else cur->right = ver, ver->par = cur;
- cur->eval();
- return splay(ver);
- }
- // root を根とする木から _key をキーとする要素を erase する(同一キーの要素が複数ある場合はどれかひとつだけ消す)
- // _key をキーとする要素がない場合は第 2 引数として false を返す.
- template<typename _Key, typename _Tp>
- pair<node<_Key, _Tp>*, bool> erase(const _Key _key, node<_Key, _Tp>* root){
- pair<node<_Key, _Tp>*, bool> ver = find(_key, root);
- assert(ver.second);
- node<_Key, _Tp> *l = ver.first->left, *r = ver.first->right;
- if(l) l->par = nullptr;
- if(r) r->par = nullptr;
- delete ver.first;
- return make_pair(join(l, r), true);
- }
- // root を根とする木を (_key 未満, _key 以上) の木に split する.
- // lower_bound ⇒ get に変えるとキー値ベースではなく個数ベースで split できる.
- template<typename _Key, typename _Tp>
- pair<node<_Key, _Tp>*, node<_Key, _Tp>*> split_key(const _Key _key, node<_Key, _Tp>* root) noexcept {
- pair<node<_Key, _Tp>*, bool> res = lower_bound(_key, root);
- if(!res.second) return make_pair(res.first, nullptr);
- node<_Key, _Tp> *res1 = nullptr, *res2 = res.first;
- res1 = res2->left, res2->left = nullptr, res2->eval();
- if(res1) res1->par = nullptr;
- return make_pair(res1, res2);
- }
- // root を根とする木のうちキー値が [lkey, rkey) のものに対して x の更新を行う.
- template<typename _Key, typename _Tp>
- node<_Key, _Tp>* range(_Key lkey, _Key rkey, _Tp x, node<_Key, _Tp>* root) noexcept {
- auto pnn1 = split_key(lkey, root);
- auto pnn2 = split_key(rkey, pnn1.second);
- if(pnn2.first) node<_Key, _Tp>::opr1(pnn2.first->lazy, x);
- return join(pnn1.first, join(pnn2.first, pnn2.second));
- }
- // root を根とする木のうちキー値が [lkey, rkey) のものに対するクエリに答える.
- // 返り値は(木の根, 値)
- template<typename _Key, typename _Tp>
- pair<node<_Key, _Tp>*, _Tp> query(_Key lkey, _Key rkey, node<_Key, _Tp>* root) noexcept {
- auto pnn1 = split_key(lkey, root);
- auto pnn2 = split_key(rkey, pnn1.second);
- _Tp res = (pnn2.first ? pnn2.first->al : node<_Key, _Tp>::id2);
- return make_pair(join(pnn1.first, join(pnn2.first, pnn2.second)), res);
- }
Atcoder : データ構造
提出コード(非想定解)
Atcoder : Hash Swapping
提出コード