SP7734 题解
这道题和文艺平衡树是双倍经验。
为了不会的同学们,我还是讲一讲。
详见我的博客园
fhq Treap
普通的 Treap 每次都要旋来旋去的,泰麻饭啦!于是出现了 fhq treap,也就是无旋 treap。
fhq treap 整体是拥有二叉搜索树的性质,但是它的每一个节点都会有一个附加权值,它的附加权值是符合堆的性质。附加权值需要随机,这样能让他尽量平衡,防止成一条链(当然也有可能成链,不过比出门被核弹创死的可能性还要低)。
treap 主要有两个操作 split 和 merge,也就是分裂与合并。
split
思想就是把一个 treap 分成两个。
用两种方法:按值分裂、按大小分裂。
首先是按值分裂,
这个就是按照他的权值,因为满足二叉搜索树,所以只需要判断比当前节点大还是小,就可以知道要分得值是在在左边还是右边。
void split(int p,int x,int &l,int &r){//分裂
if(!p){
l=r=0;
return ;
}
if(tree[p].key<=x){//判断权值是小还是大,根据权值去找比他小的。
l=p;
split(tree[l].r,x,tree[l].r,r);
}else{
r=p;
split(tree[r].l,x,l,tree[r].l);
}
pushup(p);//标记上传
}
然后就是按大小分裂:
void split(int p,int x,int &l,int &r) {
if(p==0){
l=r=0;
return;
}
if(tree[tree[p].l].size+1<=x){
l=p;
split(tree[p].r,x-tree[tree[p].l].x-1,tree[p].r,r);
}
else{
r=p;
split(tree[p].l,x,l,tree[p].l);
}
pushup(p);
}
merge
将两棵平衡树合起来,同时满足其 heap 值的堆性质,返回合并后的根序号,保证以
当两棵子树其中有一棵为空时,将根设为
当
否则,将当前根设为
int merge(int l,int r){//合并
if(!l||!r)
return l+r;
if(tree[l].val<=tree[r].val){
tree[l].r=merge(tree[l].r,r);
pushup(l);
return l;
}else{
tree[r].l=merge(l,tree[r].l);
pushup(r);
return r;
}
}
好,fhq treap 的基本操作差不多讲完了,现在来谈谈这道题。
翻转
然后捏,由于上文说过,分裂的时候可以按照大小来划分,那么只需要将比
fhq_Treep.splitq(rt,y,dl,dr);
fhq_Treep.splitq(dl,x-1,dl,p);
tree[p].lazy^=1;
rt=fhq_Treep.mergeq(fhq_Treep.mergeq(dl,p),dr);
Code
#include<bits/stdc++.h>
using namespace std;
const int N=500005;
inline int read()
{
int f = 1, res = 0;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
res = (res << 3ll) + (res << 1ll) + c - '0';
c = getchar();
}
return f * res;
}
int n,m,cnt,dl,dr,tmp,rt,p;
int y,x;
struct node{
int l,r,val,key,size,lazy;
}tree[N];
struct FHQ_Treep{
int getrand(int x){
tree[++cnt].val=x;
tree[cnt].key=rand();//防止成链
tree[cnt].size=1;
tree[cnt].l=0;
tree[cnt].r=0;
return cnt;
}
void pushup(int p){
tree[p].size=tree[tree[p].l].size+tree[tree[p].r].size+1;
}
void pushdown(int u){//下传懒标记
swap(tree[u].l,tree[u].r);
tree[tree[u].l].lazy^=1;
tree[tree[u].r].lazy^=1;
tree[u].lazy=0;
}
void splitq(int p,int x,int &l,int &r){
if(!p){
l=r=0;
return ;
}
if(tree[p].lazy)
pushdown(p);
if(tree[tree[p].l].size+1<=x){
l=p;
splitq(tree[p].r,x-tree[tree[p].l].size-1,tree[p].r,r);
}
else{
r=p;
splitq(tree[p].l,x,l,tree[p].l);
}
pushup(p);
}
int mergeq(int l,int r){//合并
if(!l||!r)
return l+r;
if(tree[l].key<tree[r].key){
if(tree[l].lazy)
pushdown(l);
tree[l].r=mergeq(tree[l].r,r);
pushup(l);
return l;
}
else{
if(tree[r].lazy)
pushdown(r);
tree[r].l=mergeq(l,tree[r].l);
pushup(r);
return r;
}
}
void print(int x){
if(tree[x].lazy){
pushdown(x);
}
if(tree[x].l)
print(tree[x].l);
printf("%d ",tree[x].val);
if(tree[x].r)
print(tree[x].r);
}
}fhq_Treep;
int main(){
n=read();m=read();
for(int i=1;i<=n;++i)
rt=fhq_Treep.mergeq(rt,fhq_Treep.getrand(i));
for(int i=1;i<=m;++i){
x=read();y=read();
fhq_Treep.splitq(rt,y,dl,dr);
fhq_Treep.splitq(dl,x-1,dl,p);
tree[p].lazy^=1;
rt=fhq_Treep.mergeq(fhq_Treep.mergeq(dl,p),dr);
}
fhq_Treep.print(rt);
return 0;
}