Splay(伸展树)实现可分裂与合并的序列

对于BST,除了Treap树之外,还有一种Splay的伸展树,他能快速的分裂与合并。

重要的操作是伸展操作,将一个指定的结点 x 旋转到根的过程。

分三种情况,一次单旋,两次同向单旋,两次反向旋转。可以手动模拟一下这个过程。

到这里,问题常常是将序列的第 k 个元素旋转到根。

首先,要知道的是伸展树里面v存的是什么,是节点的编号(下标)。这样才能像 Treap实现名次树那样,很方便的找到左边第 k 个元素。

//将序列左数第k个元素选择到根
void splay(Node* &o,int k) {   o->pushdown();   int d = o->cmp(k);   if(d==1) k-=o->ch[0]->s + 1;   if(d!=-1) {       Node* p = o->ch[d]; ​       p->pushdown();       int d2 = p->cmp(k);       int k2 = (d2==0 ? k : k - p->ch[0]->s - 1);       if(d2!=-1) {           splay(p->ch[d2],k2);           if(d==d2) rotate(o,d^1);           else rotate(o->ch[d],d);       }       rotate(o,d^1);   } }

分裂与合并:

分裂:从序列从左第 k 个元素分裂,就是将序列的 o 的第 K 小元素伸展到根,断开树根与右子节点。

合并:将left部分最大的元素旋转到根,将right作为 left的右子树。(保证right>left所有元素)。

// 合并操作。假定left所有元素小于 right
Node* merge(Node* left,Node* right) {   splay(left,left->s);   left->ch[1] = right;   left->maintain();   return left; } ​ //把 o 前 k 个小结点放到left里面,其他放到ritht里面,如果不够right = null void split(Node* o,int k,Node* &left,Node* &right) {   splay(o,k);   left = o;   right = o->ch[1];   o->ch[1] = null;   left->maintain(); }

有时,对于序列有反转操作,这时,利用 线段树的 lazy标记,标记某一段是否反转。

对于,数据结构的定义:用一个Node数组,和一个Node 的 root指针,指向这个数组的元素。

#include <bits/stdc++.h>using namespace std;struct Node {Node *ch[2];int s;int flip;int v;int cmp(int k) const {int d = k - ch[0]->s;if(d==1) return -1;     //序列第 k 个找到return d <=0 ? 0 : 1;}void maintain() {s = ch[0]->s + ch[1]->s + 1;}void pushdown() {if(flip) {flip = 0;swap(ch[0],ch[1]);ch[0]->flip = !ch[0]->flip;ch[1]->flip = !ch[1]->flip;}}
};Node *null = new Node();// d = 0 左旋
void rotate(Node* &o,int d) {Node* k = o->ch[d^1];o->ch[d^1] = k->ch[d];k->ch[d] = o;o->maintain();k->maintain();o = k;
}//将序列左数第k个元素选择到根
void splay(Node* &o,int k) {o->pushdown();int d = o->cmp(k);if(d==1) k-=o->ch[0]->s + 1;if(d!=-1) {Node* p = o->ch[d];p->pushdown();int d2 = p->cmp(k);int k2 = (d2==0 ? k : k - p->ch[0]->s - 1);if(d2!=-1) {splay(p->ch[d2],k2);if(d==d2) rotate(o,d^1);else rotate(o->ch[d],d);}rotate(o,d^1);}
}// 合并操作。假定left所有元素小于 right
Node* merge(Node* left,Node* right) {splay(left,left->s);left->ch[1] = right;left->maintain();return left;
}//把 o 前 k 个小结点放到left里面,其他放到ritht里面,如果不够right = null
void split(Node* o,int k,Node* &left,Node* &right) {splay(o,k);left = o;right = o->ch[1];o->ch[1] = null;left->maintain();
}const int maxn = 1e5+10;
struct SplaySequence {int n;Node seq[maxn];Node *root;Node* build(int sz) {if(!sz) return null;Node* L = build(sz/2);Node* o = &seq[++n];o->v = n;o->ch[0] = L;o->ch[1] = build(sz-sz/2-1);o->flip = o ->s = 0;o->maintain();return o;}void init(int sz) {n = 0;null->s = 0;root = build(sz);for(int i = 0; i < sz; i++)printf("%d ",seq[i].v);puts("");}};vector<int> ans;
void print(Node* o) {if(o!=null) {o->pushdown();print(o->ch[0]);ans.push_back(o->v);print(o->ch[1]);}
}void debug(Node* o) {if(o!=null) {o->pushdown();debug(o->ch[0]);printf("%d \n",o->v -1);debug(o->ch[1]);}
}SplaySequence ss;int main()
{int n,m;scanf("%d%d",&n,&m);ss.init(n+1);debug(ss.root);for(int i = 0; i < m; i++) {int a,b;scanf("%d%d",&a,&b);Node* left,*mid,*right,*o;split(ss.root,a,left,o);split(o,b-a+1,mid,right);mid->flip ^=1;ss.root = merge(merge(left,right),mid);}print(ss.root);for(int i = 1; i < (int)ans.size(); i++)printf("%d\n",ans[i]-1);return 0;
}

转载于:https://www.cnblogs.com/TreeDream/p/7554716.html

Uva 11922 Splay相关推荐

  1. oracle备份数据表叫什么,oracle备份表和数据

    oracle 备份数据 如果备份表存在 原表t_base_employee,备份表t_base_employee20180718 insert into t_base_employee0718 sel ...

  2. 二逼平衡树——树套树(线段树套Splay平衡树)

    题面 Bzoj3196 解析 线段树和Splay两棵树套在一起,常数直逼inf,但最终侥幸过了 思路还是比较简单, 在原数组维护一个下标线段树,再在每一个线段树节点,维护一个对应区间的权值Splay. ...

  3. [搜索]UVa 129 困难的串

    题意:将一个包含两个相邻的重复子串的子串,称为"容易的串",其他为"困难的串". 输入正整数n和l,输出由前l个字符组成的,字典序第n小的困难的串. 输入样例: ...

  4. 简析平衡树(三)——浅谈Splay

    前言 原本以为\(Treap\)已经很难了,学习了\(Splay\),我才知道,没有最难,只有更难.(强烈建议先去学一学\(Treap\)再来看这篇博客) 简介 \(Splay\)是平衡树中的一种,除 ...

  5. AVL树、splay树(伸展树)和红黑树比较

    AVL树.splay树(伸展树)和红黑树比较 一.AVL树: 优点:查找.插入和删除,最坏复杂度均为O(logN).实现操作简单 如过是随机插入或者删除,其理论上可以得到O(logN)的复杂度,但是实 ...

  6. uva 401.Palindromes

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...

  7. Uva 3767 Dynamic len(set(a[L:R])) 树套树

    Dynamic len(set(a[L:R])) Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://uva.onlinejudge.org/in ...

  8. UVA 11752 超级幂

    UVA 11752 超级幂 Z - The Super Powers Time Limit:1000MS     Memory Limit:0KB     64bit IO Format:%lld & ...

  9. UVa 11174 - Stand in a Line

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

最新文章

  1. nginx之 nginx-1.9.7 编译安装、理论简介
  2. js中的if与Java中的if_JavaScript if...else 语句
  3. jquery 封装页面之间获取值
  4. String 重载 + 原理分析
  5. mysqli 返回一条结果_php中mysqli 处理查询结果集总结
  6. delphi socket 怎样把接收到的二进制数据转换成字符串显示_广东qp用户数据免费咨询...
  7. 【NOI2018】你的名字【后缀自动机】【可持久化线段树合并】【乱搞】
  8. 10深入Redis Cluster
  9. ul列表中包含input时line-height属性失效的解决办法
  10. 五大列级庄_酒庄拉菲古堡Chateau Lafite Rothschild, 波尔多五大一级庄之首
  11. Deep Ordinal Regression Network for Monocular Depth Estimation
  12. mysql 历史数据迁移,MySQL 历史数据表迁移方法
  13. 三星s4流量显示无服务器,三星s4有什么隐藏功能
  14. 7-1 统计大写辅音字母 (15 分)
  15. mysql导入excel表_mysql怎么导入excel数据?
  16. 数据结构复习题(一)
  17. Matlab------如何控制matlab中的数据输出格式
  18. 如何在Ubuntu 20.04上安装Kvm
  19. 如何使用windows自带远程桌面连接linux,使用Windows自带远程桌面应用连接CentOS8远程桌面...
  20. CPL, 门DPL, 描述符DPL 的关系

热门文章

  1. 物理光学11 衍射的基本概念与惠更斯原理
  2. UA SIE545 优化理论基础1 例题3 凸多面体的表示与线性规划
  3. WPF 故事板动画示例
  4. 图解分析一个dNet进销存软件
  5. 3d数学基础学习总结
  6. MSI文件、工具、资料
  7. 纯手工服务器维护教程
  8. Windows XP Embedded 上手指南
  9. CAFFE(0):Ubuntu 下安装anaconda2和anaconda3
  10. 解决J2EE系统应用性能问题常用方法