终于写了一次可持久化Treap,做的是可持久化序列的模板题。

Treap

Treap=Tree+Heap,是一个随机化的数据结构。它的每个节点至少有两个关键字,一个是我们要存储的\(val\),一个是随机堆关键字,我把它称为\(hp\)。Treap满足的性质是\(val\)从小到大,并且每个节点的\(hp\)都小于(或都大于)儿子节点的\(hp\)值。也就是说,通过一个随机数来让Treap具有堆的性质,从而使得其期望深度为\(O(logn)\)。

旋转

Treap可以通过旋转来保持其平衡,操作与splay类似。

非旋转

非旋转Treap是本文的重点。由于Treap同时具有二叉搜索树和堆的性质,我们考虑利用堆的性质来保持平衡。想一想之前提到过的左偏树的平衡方法,我们可以得到一个基于SplitMerge操作的Treap,称为非旋转Treap。

Split

\(split(x,k)\)返回一个\(pair\),表示把\(x\)为根的树的前\(k\)个元素放在一颗树中,后面的放在另一颗树中,返回这两棵树的根。

这个操作实现起来非常简单。如果\(x\)的左子树的\(size\ge k\),那么直接递归进左子树,把左子树分出来的第二颗树和当前的\(x\)和右子树合并。否则递归右子树。写的时候注意一下顺序即可。

Merge

\(merge(x,y)\)返回merge出的树的根。同样递归实现。如果\(hp(x)<hp(y)\),则\(merge(rc(x),y)\),否则\(merge(x,lc(y))\)。

非旋转Treap的关键在于不需要维护父亲节点的信息,故可以可持久化!

每次split和merge走到的所有点都新建一个即可。注意下传标记也要新建点。

代码

可持久化序列这道题要求支持三个操作:

  • \(\text{1 l r}\),翻转\(l\)到\(r\)的区间
  • \(\text{2 l r}\),询问\(l\)的到\(r\)的区间和
  • \(\text{3 p}\),回到\(p\)时刻

每次修改新建点打翻转标记即可。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<algorithm>
using namespace std;
typedef pair<int,int> Pair;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=5e4+5;
const int nlogn=1.3e7+5;
struct node {
int x,hp,l,r,sum,size;
bool rev;
void clear() {
x=hp=l=r=sum=size=rev=0;
}
};
struct TREAP {
int pool[nlogn];
int pooler;
node t[nlogn];
int now,all;
int root[maxn];
TREAP ():now(0),pooler(1) {
for (int i=1;i<nlogn;++i) pool[i]=i;
root[now]=pool[pooler++];
}
int newroot() {
int ret=pool[pooler++];
return ret;
}
int newnode(int x) {
int ret=pool[pooler++];
t[ret].hp=rand();
t[ret].size=1;
t[ret].x=t[ret].sum=x;
return ret;
}
void delnode(int x) {
t[x].clear();
pool[--pooler]=x;
}
void next() {
root[++all]=newroot();
t[root[all]]=t[root[now]];
now=all;
}
void back(int x) {
now=x;
}
void update(int x) {
t[x].sum=t[x].x+t[t[x].l].sum+t[t[x].r].sum;
t[x].size=t[t[x].l].size+t[t[x].r].size+1;
}
void pushdown(int x) {
if (!t[x].rev) return;
if (t[x].l) {
int tx=newnode(t[t[x].l].x);
t[tx]=t[t[x].l];
t[tx].rev^=true;
t[x].l=tx;
}
if (t[x].r) {
int tx=newnode(t[t[x].r].x);
t[tx]=t[t[x].r];
t[tx].rev^=true;
t[x].r=tx;
}
swap(t[x].l,t[x].r);
t[x].rev=false;
}
int merge(int x,int y) {
if (!x) return y;
if (!y) return x;
int now;
if (t[x].hp<=t[y].hp) {
now=newnode(t[x].x);
t[now]=t[x];
pushdown(now);
t[now].r=merge(t[now].r,y);
} else {
now=newnode(t[y].x);
t[now]=t[y];
pushdown(now);
t[now].l=merge(x,t[now].l);
}
update(now);
return now;
}
Pair split(int x,int p) {
if (t[x].size==p) return make_pair(x,0);
int now=newnode(t[x].x);
t[now]=t[x];
pushdown(now);
int l=t[now].l,r=t[now].r;
if (t[l].size>=p) {
t[now].l=0;
update(now);
Pair g=split(l,p);
now=merge(g.second,now);
return make_pair(g.first,now);
} else if (t[l].size+1==p) {
t[now].r=0;
update(now);
return make_pair(now,r);
} else {
t[now].r=0;
update(now);
Pair g=split(r,p-t[l].size-1);
now=merge(now,g.first);
return make_pair(now,g.second);
}
}
void rever(int l,int r) {
++l,++r;
Pair g=split(root[now],l-1);
Pair h=split(g.second,r-l+1);
int want=h.first;
int here=newnode(t[want].x);
t[here]=t[want];
t[here].rev^=true;
int fi=merge(g.first,here);
int se=merge(fi,h.second);
root[now]=se;
}
int query(int l,int r) {
++l,++r;
Pair g=split(root[now],l-1);
Pair h=split(g.second,r-l+1);
int want=h.first;
int ret=t[want].sum;
int fi=merge(g.first,want);
int se=merge(fi,h.second);
root[now]=se;
return ret;
}
void insert(int x) {
int k=newnode(x);
root[now]=merge(root[now],k);
}
} Treap;
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("my.out","w",stdout);
#endif
srand(time(0));
int n=read(),m=read();
for (int i=1;i<=n;++i) {
int x=read();
Treap.insert(x);
}
while (m--) {
int op=read();
if (op==1) {
Treap.next();
int l=read(),r=read();
Treap.rever(l,r);
} else if (op==2) {
int l=read(),r=read();
int ans=Treap.query(l,r);
printf("%d\n",ans);
} else if (op==3) {
Treap.back(read());
}
}
return 0;
}

可持久化Treap的更多相关文章

  1. UVALive 6145 Version Controlled IDE(可持久化treap、rope)

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...

  2. BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap

    3595: [Scoi2014]方伯伯的Oj Time Limit: 6 Sec  Memory Limit: 256 MBSubmit: 102  Solved: 54[Submit][Status ...

  3. 【模板】可持久化文艺平衡树-可持久化treap

    题目链接 题意 对于各个以往的历史版本实现以下操作: 在第 p 个数后插入数 x . 删除第 p 个数. 翻转区间 [l,r],例如原序列是 \(\{5,4,3,2,1\}\),翻转区间 [2,4] ...

  4. 高rong效chang的可持久化treap

    很多人觉得可持久化treap很慢,但是事实上只是他们可持久化treap的写法不对.他们一般是用split和merge实现所有功能,但是这样会有许多不必要的分裂.其实我们可以用一种特殊的方式来实现插入和 ...

  5. Codeforces - 38G 可持久化Treap 区间操作

    题意:\(n\)个人排队,每个人有重要度\(p\)和不要脸度\(c\),如果第\(i\)个人的重要度大于第\(i-1\)个人的重要度,那么他们之间可以交换,不要脸度-1,交换后先前的第\(i\)个人也 ...

  6. Codeforces - 675D 可持久化Treap 树形操作

    题意:模拟二叉树的构造过程,给出\(n\)个节点,每次从根插入,小于当前节点转到左儿子,否则右儿子,输出第\([2,n]\)个节点的父亲的权值 直接手动模拟会被链式结构T掉 网上找了下发现二叉树的性质 ...

  7. 平衡树与可持久化treap

    平衡树(二叉树) 线段树不支持插入or删除一个数于是平衡树产生了 常见平衡树:treap(比sbt慢,好写吧),SBT(快,比较好写,有些功能不支持),splay(特别慢,复杂度当做根号n来用,功能强 ...

  8. 脑洞大开加偏执人格——可持久化treap版的Link Cut Tree2

    试了一下先上再下的Treap方式,很高兴,代码变短了,但是,跑的变慢了!!!其实慢得不多,5%左右.而且这个版本的写法不容易写错..只要会一般可持久化Treap的人写着都不难...就是相对于(压行的) ...

  9. 脑洞大开加偏执人格——可持久化treap版的Link Cut Tree

    一直没有点动态树这个科技树,因为听说只能用Splay,用Treap的话多一个log.有一天脑洞大开,想到也许Treap也能从底向上Split.仔细思考了一下,发现翻转标记不好写,再仔细思考了一下,发现 ...

随机推荐

  1. 引用ZXing生成二维码

    1.生成二维码 ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口. Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码.本文引用 ...

  2. QT Creator 转VS2017+QT工程

    因为刚学QT 不熟悉其QT Creator 的开发环境,所以打算用VS2017来开发,因为要跨平台所以打算写出来的代码可以放在linux上编译. 这时就需要将VS2017的工程转换成QT Creato ...

  3. 北京Uber优步司机奖励政策(12月25日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  4. 佛山Uber优步司机奖励政策(12月14日到12月20日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  5. CF 643 E. Bear and Destroying Subtrees

    E. Bear and Destroying Subtrees http://codeforces.com/problemset/problem/643/E 题意: Q个操作. 加点,在原来的树上加一 ...

  6. Android ObjectOutputStream Serializable引发的血案

    遇到一个问题 安装后第二次进app,闪退 重现步骤 [前置条件] 打包分支:dev_7.13 手机:vivo NEX 8.1.0 [步骤] 安装三星app----同意用户协议进入书城---连续点击ba ...

  7. 华天正real210开发板测试-第1篇

    1. 网上买的real210二手开发板,今天刚到测试一下 2. 启动方式,不过目前唯一的问题是没有开发资料,然后给原厂发了份邮件要资料,原厂爽快的给了,必须给华天正这服务态度点个赞啊 3. 调到nan ...

  8. 白话控制反转IoC及其应用

    控制反转(IoC, Inversion of Control),依赖注入(DI, Dependency Injection)是在面向对象编程中经常碰到的专业术语.很多朋友可能在百度之后,便浅尝辄止,没 ...

  9. 「日常训练」Queue(Codeforces Round 303 Div.2 D)

    简单到让人不敢相信是D题,但是还是疏忽了一点. 题意与分析 (Codeforces 545D) 题意:n人排队,当一个人排队的时间超过他需要服务的时间就会厌烦,现在要求一个最优排列使得厌烦的人最少. ...

  10. ReadyAPI创建功能测试的方法

    声明:如果你想转载,请标明本篇博客的链接,请多多尊重原创,谢谢! 本篇使用的 ReadyAPI版本是2.5.0 在ReadyAPI中有多种方法可以创建功能测试,本篇将分步操作创建功能测试. 1.从So ...