题意
给定一个 的排列,要求支持区间翻转并加到区间末尾,求所有操作完成后的结果。
思路
文艺平衡树 模板题,不过是加到区间末尾而已。
如果想学习 FHQ-Treap 请右转本人博客 关于 FHQ-Treap 和 Treap 区间操作的简析
简单来说就是不需要旋转维护平衡的平衡树,直接使用分割和合并维护平衡。
在维护二叉搜索树基本性质的基础上,随机一个值 rnd 并维护堆性质。
用途广泛,函数封装代码简单易懂,除了不能写 LCT 以外啥都好。
代码
struct FHQTreap
{
int l,r,val,rnd,siz,mark;
}tr[N];
int n,cnt=0,rt=0,m;
void update( int x )
{
tr[x].siz=tr[tr[x].l].siz+tr[tr[x].r].siz+1;
}
int new_node( int val ) //新建节点
{
cnt++; tr[cnt].siz=1; tr[cnt].rnd=rand(); tr[cnt].val=val; tr[cnt].mark=0;
return cnt;
}
void pushdown( int x ) //翻转标记下传
{
if ( !x || !tr[x].mark ) return;
tr[x].mark=0; swap( tr[x].l,tr[x].r );
if ( tr[x].l ) tr[tr[x].l].mark^=1;
if ( tr[x].r ) tr[tr[x].r].mark^=1;
update( x );
}
void split( int now,int k,int &x,int &y ) //分割(按照排名分裂)
{
if ( !now ) { x=y=0; return; }
pushdown( now );
if ( k<=tr[tr[now].l].siz ) y=now,split( tr[now].l,k,x,tr[now].l );
else x=now,split( tr[now].r,k-tr[tr[now].l].siz-1,tr[now].r,y );
update( now );
}
int merge( int x,int y ) //合并
{
if ( !x || !y ) return x+y;
pushdown( x ); pushdown( y );
if ( tr[x].rnd<tr[y].rnd )
{
tr[x].r=merge( tr[x].r,y ); update( x ); return x;
}
else
{
tr[y].l=merge( x,tr[y].l ); update( y ); return y;
}
}
void dfs( int x ) //dfs输出
{
if ( !x ) return; pushdown( x );
dfs( tr[x].l );
printf( "%d\n",tr[x].val );
dfs( tr[x].r );
}
void reverse( int l,int r )
{
int t1,t2,t3,t4;
split( rt,r,t1,t2 ); split( t1,l-1,t3,t4 );
tr[t4].mark^=1; //rt=merge( merge(t3,t4),t2 );
rt=merge( merge( t3,t2 ),t4 ); //要添加到末尾,所以不一样
} 
京公网安备 11010502036488号