Processing math: 100%
My Algorithm : kopricky アルゴリズムライブラリ

kopricky アルゴリズムライブラリ

Splay Tree

コードについての説明(個人的メモ)

lookup, insert, erase などの操作をならし計算量 O(logn) で実現する平衡二分探索木([Sleator, Tarjan '83]). 動的連結性クエリに高速に答える手法(Link Cut Tree)を考案する過程で得られたデータ構造.
以下では遅延処理(区間加算, 区間総和)を施した実装にしている.

時間計算量: 各クエリ O(logn) (ならし計算量)

コード

  1. template<typename _Key, typename _Tp> class node {
  2. public:
  3. int sz;
  4. _Key key;
  5. _Tp val, al, lazy;
  6. node *left, *right, *par;
  7. node(_Key _key, _Tp _val) noexcept : sz(1), key(_key), val(_val), al(val), lazy(id1),
  8. left(nullptr), right(nullptr), par(nullptr){}
  9. static const _Tp id1 = (_Tp)0;
  10. static const _Tp id2 = (_Tp)0;
  11. static void opr1(_Tp& arg1, const _Tp arg2){ arg1 += arg2; }
  12. static _Tp opr2(const _Tp arg1, const _Tp arg2){ return arg1 + arg2; }
  13. inline bool isRoot() const { return !par; }
  14. void push(){
  15. if(lazy != id1){
  16. opr1(val, lazy), al += lazy * sz;
  17. if(left) opr1(left->lazy, lazy);
  18. if(right) opr1(right->lazy, lazy);
  19. lazy = id1;
  20. }
  21. }
  22. void eval(){
  23. sz = 1, al = val;
  24. if(left) left->push(), sz += left->sz, al = opr2(left->al, al);
  25. if(right) right->push(), sz += right->sz, al = opr2(al, right->al);
  26. }
  27. void rotate(bool right_){
  28. node<_Key, _Tp> *p = par, *g = p->par;
  29. if(right_){
  30. if((p->left = right)) right->par = p;
  31. right = p, p->par = this;
  32. }else{
  33. if((p->right = left)) left->par = p;
  34. left = p, p->par = this;
  35. }
  36. p->eval(), eval();
  37. if(!(par = g)) return;
  38. if(g->left == p) g->left = this;
  39. if(g->right == p) g->right = this;
  40. g->eval();
  41. }
  42. };
  43.  
  44. template<typename _Key, typename _Tp>
  45. int size(node<_Key, _Tp>* u){ return u ? u->sz : 0; }
  46.  
  47. // 頂点 u を木の根にする
  48. template<typename _Key, typename _Tp>
  49. node<_Key, _Tp>* splay(node<_Key, _Tp>* u) noexcept {
  50. if(!u) return nullptr;
  51. while(!(u->isRoot())){
  52. node<_Key, _Tp> *p = u->par, *gp = p->par;
  53. if(p->isRoot()){ // zig
  54. p->push(), u->push();
  55. u->rotate((u == p->left));
  56. }else{
  57. gp->push(), p->push(), u->push();
  58. bool flag = (u == p->left);
  59. if((u == p->left) == (p == gp->left)){ // zig-zig
  60. p->rotate(flag), u->rotate(flag);
  61. }else{ // zig-zag
  62. u->rotate(flag), u->rotate(!flag);
  63. }
  64. }
  65. }
  66. u->push();
  67. return u;
  68. }
  69.  
  70. // root を根とする木の頂点で k 番目に小さいキー値のものを探索する
  71. // 返り値は (木の根, k 番目が存在するかしないか(0/1))
  72. template<typename _Key, typename _Tp>
  73. pair<node<_Key, _Tp>*, bool> get(const int k, node<_Key, _Tp>* root) noexcept {
  74. if(size(root) < k) return make_pair(root, false);
  75. int sum = 0;
  76. node<_Key, _Tp> *cur = nullptr, *nx = root;
  77. while(nx){
  78. cur = nx, cur->push();
  79. if(size(cur->left) < sum - 1){
  80. nx = cur->right, sum -= size(cur->left) + 1;
  81. }else if(size(cur->left) >= sum){
  82. nx = cur->left;
  83. }else{
  84. return make_pair(splay(cur), true);
  85. }
  86. }
  87. }
  88.  
  89. // root を根とする木の頂点でキーが _key であるものを探索する
  90. // 返り値は (木の根, 存在するかしないか(0/1))
  91. template<typename _Key, typename _Tp>
  92. pair<node<_Key, _Tp>*, bool> find(const _Key _key, node<_Key, _Tp>* root) noexcept {
  93. node<_Key, _Tp> *cur = nullptr, *nx = root;
  94. while(nx){
  95. cur = nx, cur->push();
  96. if(cur->key == _key) return make_pair(splay(cur), true);
  97. if(cur->key > _key) nx = cur->left;
  98. else nx = cur->right;
  99. }
  100. return make_pair(splay(cur), false);
  101. }
  102.  
  103. // root を根とする木の頂点でキーが _key 以上で最小のものを返す(bool は _key 以上のものがあるかないか)
  104. // _key 以上のものがなくても返り値のノードは nullptr とは限らないことに注意(_key 以上がなくても木の根は変わるので)
  105. template<typename _Key, typename _Tp>
  106. pair<node<_Key, _Tp>*, bool> lower_bound(const _Key _key, node<_Key, _Tp>* root) noexcept {
  107. node<_Key, _Tp> *cur = nullptr, *nx = root, *res = nullptr;
  108. while(nx){
  109. cur = nx, cur->push();
  110. if(cur->key >= _key){
  111. nx = cur->left;
  112. if(!res || cur->key <= res->key) res = cur;
  113. }else nx = cur->right;
  114. }
  115. node<_Key, _Tp>* tmp = splay(cur);
  116. return res ? make_pair(splay(res), true) : make_pair(tmp, false);
  117. }
  118.  
  119. // root を根とする木の頂点でキーが _key を超える最小のものを返す(bool は _key を超えるものがあるかないか)
  120. // _key を超えるものがなくても返り値のノードは nullptr とは限らないことに注意(_key を超えるものがなくても木の根は変わるので)
  121. template<typename _Key, typename _Tp>
  122. pair<node<_Key, _Tp>*, bool> upper_bound(const _Key _key, node<_Key, _Tp>* root) noexcept {
  123. node<_Key, _Tp> *cur = nullptr, *nx = root, *res = nullptr;
  124. while(nx){
  125. cur = nx, cur->push();
  126. if(cur->key > _key){
  127. nx = cur->left;
  128. if(!res || cur->key <= res->key) res = cur;
  129. }else nx = cur->right;
  130. }
  131. node<_Key, _Tp>* tmp = splay(cur);
  132. return res ? make_pair(splay(res), true) : make_pair(tmp, false);
  133. }
  134.  
  135. // root1 を根とする木のすべての要素が root 2 を根とする木のすべての要素より小さいときの merge
  136. template<typename _Key, typename _Tp>
  137. node<_Key, _Tp>* join(node<_Key, _Tp>* root1, node<_Key, _Tp>* root2) noexcept {
  138. if(!root1 || !root2) return root1 ? root1 : root2;
  139. node<_Key, _Tp> *cur = nullptr, *nx = root1;
  140. while(nx) cur = nx, cur->push(), nx = cur->right;
  141. node<_Key, _Tp>* ver = splay(cur);
  142. ver->right = root2, ver->eval(), root2->par = ver;
  143. return ver;
  144. }
  145.  
  146. // root を根とする木に ver を insert する
  147. template<typename _Key, typename _Tp>
  148. node<_Key, _Tp>* insert(node<_Key, _Tp>* ver, node<_Key, _Tp>* root) noexcept {
  149. if(!root) return ver;
  150. node<_Key, _Tp> *cur = nullptr, *nx = root;
  151. while(nx){
  152. cur = nx, cur->push();
  153. if(cur->key > ver->key) nx = cur->left;
  154. else nx = cur->right;
  155. }
  156. if(cur->key > ver->key) cur->left = ver, ver->par = cur;
  157. else cur->right = ver, ver->par = cur;
  158. cur->eval();
  159. return splay(ver);
  160. }
  161.  
  162. // root を根とする木から _key をキーとする要素を erase する(同一キーの要素が複数ある場合はどれかひとつだけ消す)
  163. // _key をキーとする要素がない場合は第 2 引数として false を返す.
  164. template<typename _Key, typename _Tp>
  165. pair<node<_Key, _Tp>*, bool> erase(const _Key _key, node<_Key, _Tp>* root){
  166. pair<node<_Key, _Tp>*, bool> ver = find(_key, root);
  167. assert(ver.second);
  168. node<_Key, _Tp> *l = ver.first->left, *r = ver.first->right;
  169. if(l) l->par = nullptr;
  170. if(r) r->par = nullptr;
  171. delete ver.first;
  172. return make_pair(join(l, r), true);
  173. }
  174.  
  175. // root を根とする木を (_key 未満, _key 以上) の木に split する.
  176. // lower_bound ⇒ get に変えるとキー値ベースではなく個数ベースで split できる.
  177. template<typename _Key, typename _Tp>
  178. pair<node<_Key, _Tp>*, node<_Key, _Tp>*> split_key(const _Key _key, node<_Key, _Tp>* root) noexcept {
  179. pair<node<_Key, _Tp>*, bool> res = lower_bound(_key, root);
  180. if(!res.second) return make_pair(res.first, nullptr);
  181. node<_Key, _Tp> *res1 = nullptr, *res2 = res.first;
  182. res1 = res2->left, res2->left = nullptr, res2->eval();
  183. if(res1) res1->par = nullptr;
  184. return make_pair(res1, res2);
  185. }
  186.  
  187. // root を根とする木のうちキー値が [lkey, rkey) のものに対して x の更新を行う.
  188. template<typename _Key, typename _Tp>
  189. node<_Key, _Tp>* range(_Key lkey, _Key rkey, _Tp x, node<_Key, _Tp>* root) noexcept {
  190. auto pnn1 = split_key(lkey, root);
  191. auto pnn2 = split_key(rkey, pnn1.second);
  192. if(pnn2.first) node<_Key, _Tp>::opr1(pnn2.first->lazy, x);
  193. return join(pnn1.first, join(pnn2.first, pnn2.second));
  194. }
  195.  
  196. // root を根とする木のうちキー値が [lkey, rkey) のものに対するクエリに答える.
  197. // 返り値は(木の根, 値)
  198. template<typename _Key, typename _Tp>
  199. pair<node<_Key, _Tp>*, _Tp> query(_Key lkey, _Key rkey, node<_Key, _Tp>* root) noexcept {
  200. auto pnn1 = split_key(lkey, root);
  201. auto pnn2 = split_key(rkey, pnn1.second);
  202. _Tp res = (pnn2.first ? pnn2.first->al : node<_Key, _Tp>::id2);
  203. return make_pair(join(pnn1.first, join(pnn2.first, pnn2.second)), res);
  204. }

verify 用の問題

Atcoder : データ構造 提出コード(非想定解)
Atcoder : Hash Swapping 提出コード