文艺平衡树
翻转子序列
平衡树进行序列操作是在下标为权值的基础上建立的平衡树 这样做会有几个性质:
- 一颗子树代表着一个子序列
- 不记录下标 树的形态就是序列的形态 平衡树上只记录数值
- 对于初始序列 我们可以直接建树
#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
using namespace std;
const int N=2e5+10;
int read()
{
int x=0,f=0,c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return f?-x:x;
}
int sz[N],lch[N],rch[N],rnd[N],val[N];
int root,rx,ry,rz,cnt;
bool tag[N];
int n,m;
void upd(int x){ sz[x]=sz[lch[x]]+sz[rch[x]]+1;}
void down(int x)
{
swap(lch[x],rch[x]);
tag[lch[x]]^=1; tag[rch[x]]^=1;
tag[x]=0;
}
void split(int now,int k,int &x,int &y)
{
if(!now){ x=y=0; return;}
if(tag[now]) down(now);
if(k>=sz[lch[now]]+1) x=now,split(rch[now],k-sz[lch[now]]-1,rch[x],y);//注意 此处易错
else y=now,split(lch[now],k,x,lch[y]);
upd(now);
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
if(rnd[x]<rnd[y])
{
if(tag[x]) down(x);
rch[x]=merge(rch[x],y); upd(x); return x;
}
else
{
if(tag[y]) down(y);
lch[y]=merge(x,lch[y]); upd(y); return y;
}
}
//下标=序列权值 =平衡树权值
int _new(int x){ sz[++cnt]=1;rnd[cnt]=rand();val[cnt]=x; return cnt;}
void print(int x)
{
if(!x)return;
if(tag[x]) down(x);
print(lch[x]);
printf("%d ",val[x]);
print(rch[x]);
}
void debug(int x)
{
if(!x) return;
cout<<x<<" "<<lch[x]<<" "<<rch[x]<<endl;
debug(lch[x]);
printf("%d %d\n",x,val[x]);
debug(rch[x]);
}
int main()
{
srand( time(0));
n=read(); m=read();
for(int i=1;i<=n;i++)
root=merge(root,_new(i));
for(int i=1;i<=m;i++)
{
int l=read(),r=read();
split(root,r,rx,rz);
split(rx,l-1,rx,ry);
tag[ry]^=1;
root=merge( merge(rx,ry),rz ) ;
}
print(root);
return 0;
}
注意:
- 按照排名分裂的时候记得要减去paiming
- 在合并和分裂的时候都要下传标记 因为树的形态会改变
- 交换的时候交换的是整个儿子 意味着序列的形态直接发生变化 交换的是两颗子树 如果只交换信息 那么代表着两个点的信息发生变化

浙公网安备 33010602011771号