在学习平衡树部分时,旁边的某位C姓dalao对Treap情有独钟,而我却为Splay的优美而深深着迷.这导致了对Treap的不屑一顾
这东西有什么用,那么多操作都不资瓷,low
如今繁华落尽,每次遇到需要使用平衡树的题时,不禁流下了悔恨的泪(汗)水
Splay真xx**难打!
所以,今天,就让我们来讲讲无旋Treap
无旋Treap最大的优势就是编码简单,支持的操作多,相应的,它比Splay要稍稍慢一点
无旋Treap的主要操作有两个,split
和merge
,能分裂 or o r 合并两棵Treap.通过这两个操作,就可以拓展出大量的其他操作
Treap的split
支持在某棵Treap中分裂出大小为 num n u m 的左子树,或者是分裂出权值小于 k k 的子树
由于Treap具有二叉搜索树的性质,按size
or o r key
递归分裂即可
同时通过对象维护分裂后两颗treap各自的位置关系
按size
分裂
void split(int now,int num,int &x,int &y) {
if(!now) x=y=0;
else {
pushdown(now);
if(num<=siz[L]) {y=now;split(L,num,x,L);}
else {x=now;split(R,num-siz[L]-1,R,y);}
update(now);
}
}
按key
分裂
void split(int now,int k,int &x,int &y) {
if(!now) x=y=0;
else {
//小于k的在左子树,大于等于key的在右子树
if(kelse {x=now;split(R,k,R,y);}
update(now);
}
}
Treap的合并操作将两棵Treap以一定的次序组合起来
其最终形态由两方面决定:相对位置
和pos
(我通常将其叫做自平衡权)
显然,根据Treap的原理,通常pos
较小的放在靠上的位置,同时treap又是二叉搜索树,那么其相对位置决定了两者之间的父子关系(属于左子树 or o r 右子树)
类似与左偏树一样,递归合并即可
int merge(int a,int b) {
if(a*b==0) return a+b;
if(pos[a]1]=merge(ch[a][1],b);
update(a);
return a;
}
else {
ch[b][0]=merge(a,ch[b][0]);
update(b);
return b;
}
}
通过split
和merge
,我们可以简单的实现insert
首先将要插入的位置左侧部分分裂出来,然后依次合并左侧部分,插入节点,右侧部分即可
同理,将小于 v v 的节点放在左子树,依次合并
void insert(int v) {
int a,b;
split(rt,v,a,b);
rt=merge(merge(a,make_node(v)),b);
}
通过split
和merge
,我们可以简单的实现del
把删除位置提取出来,合并左右节点
把小于等于k的节点提取出来,再小于k-1的的部分提取出来,由于可能有多等于 k k 的值,直接将等于 k k 的子树合并左右儿子节点,这样就保证了仅仅删除一个节点.若要全部删除,直接合并左右部分
void del(int v) {
int a,b,c;
split(rt,v,a,b);
split(a,v-1,a,c);
c=merge(ch[c][0],ch[c][1]);
rt=merge(merge(a,c),b);
}
类似于splay
,先利用split
提取区间,然后打上标记,最后merge
比如说,区间翻转
void rev(int l,int r) {
split(rt,r+1,a,b);
split(a,l,c,d);
rev[d]^=1;
swap(ch[d][0],ch[d][1]);
}
#include
using namespace std;
#define L ch[now][0]
#define R ch[now][1]
#define mid ((l+r)>>1)
typedef pair <int,int> p;
const int N = 100010;
int n,m,rt;
struct treap {
int pos[N],ch[N][2],siz[N],rev[N],rt,key[N];
void update(int now) {siz[now]=siz[L]+siz[R]+1;}
void Rev(int now) {swap(L,R);}
void pushdown(int now) {if(rev[now]) {rev[now]^=1;rev[L]^=1;rev[R]^=1;Rev(L);Rev(R);}}
int merge(int a,int b) {
if(a*b==0) return a?a:b;
pushdown(a);pushdown(b);
if(pos[a]1]=merge(ch[a][1],b);
update(a);
return a;
}
else {
ch[b][0]=merge(a,ch[b][0]);
update(b);
return b;
}
}
void split(int now,int num,int &x,int &y) {
if(!now) x=y=0;
else {
pushdown(now);
if(num<=siz[L]) {y=now;split(L,num,x,L);}
else {x=now;split(R,num-siz[L]-1,R,y);}
update(now);
}
}
int build(int l,int r) {
if(l==r) {pos[l]=rand();siz[l]=1;key[l]=l-1;return l;}
return merge(build(l,mid),build(mid+1,r));
}
void print(int now) {
pushdown(now);
if(L) print(L);
if(key[now]>=1 && key[now]<=n) printf("%d ",key[now]);
if(R) print(R);
}
}t;
int read() {
int _ans=0,_flag=1;
char _ch=getchar();
while((_ch != '-') && (_ch > '9' || _ch < '0')) _ch=getchar();
if(_ch == '-') {_flag = -1;_ch = getchar();}
while(_ch >= '0' && _ch <= '9') {_ans=_ans*10+_ch-'0';_ch=getchar();}
return _ans*_flag;
}
int main() {
n=read();m=read();
rt=t.build(1,n+2);
for(int i=1;i<=m;++i) {
int l=read(),r=read(),a,b,c,d;
t.split(rt,r+1,a,b);
t.split(a,l,c,d);
t.rev[d]^=1;
t.Rev(d);
rt=t.merge(c,t.merge(d,b));
}
t.print(rt);
return 0;
}
#include
using namespace std;
#define L ch[now][0]
#define R ch[now][1]
const int N = 400010;
map <int,int> p;
struct Treap {
int key[N],pos[N],cnt,ch[N][2],rt[N],siz[N];
int newnode(int k) {pos[++cnt]=rand();siz[cnt]=1;key[cnt]=k;return cnt;}
void update(int now) {siz[now]=1+siz[L]+siz[R];}
void split(int now,int k,int &x,int &y) {
if(!now) {x=y=0;return;}
if(kelse {x=now;split(R,k,R,y);}
update(now);
}
int merge(int a,int b) {
if(a*b==0) return a+b;
if(pos[a]1]=merge(ch[a][1],b);
update(a);
return a;
}
else {
ch[b][0]=merge(a,ch[b][0]);
update(b);
return b;
}
}
void insert(int k,int v) {
int a,b;
split(rt[k],v,a,b);
rt[k]=merge(a,merge(newnode(v),b));
}
void del(int k,int v) {
int a,b,c;
split(rt[k],v,a,b);
split(a,v-1,a,c);
c=merge(ch[c][0],ch[c][1]);
rt[k]=merge(merge(a,c),b);
}
void query(int k,int l,int r) {
int a,b,c;
split(rt[k],r,a,b);
split(a,l-1,a,c);
printf("%d\n",siz[c]);
rt[k]=merge(merge(a,c),b);
}
}t;
int n,m,cnt,a[N];
int read();
int main() {
srand(time(NULL));
n=read();m=read();
for(int i=1;i<=n;++i) {
a[i]=read();
if(p[a[i]]==0) p[a[i]]=++cnt;
a[i]=p[a[i]];
t.insert(a[i],i);
}
for(int i=1;i<=m;++i) {
char ch=getchar();
while(ch!='Q' && ch!='C') ch=getchar();
if(ch=='Q') {
int l=read(),r=read(),k=read();
k=p[k];
t.query(k,l,r);
}
else {
int pos=read(),k=read();
t.del(a[pos],pos);
if(p[k]==0) p[k]=++cnt;
a[pos]=p[k];
t.insert(a[pos],pos);
}
}
return 0;
}
int read() {
int _ans=0,_flag=1;
char _ch=getchar();
while((_ch != '-') && (_ch > '9' || _ch < '0')) _ch=getchar();
if(_ch == '-') {_flag = -1;_ch = getchar();}
while(_ch >= '0' && _ch <= '9') {_ans=_ans*10+_ch-'0';_ch=getchar();}
return _ans*_flag;
}