文艺平衡树

翻转子序列

平衡树进行序列操作是在下标为权值的基础上建立的平衡树 这样做会有几个性质:

  1. 一颗子树代表着一个子序列
  2. 不记录下标 树的形态就是序列的形态 平衡树上只记录数值
  3. 对于初始序列 我们可以直接建树
#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;
}

注意:

  1. 按照排名分裂的时候记得要减去paiming
  2. 在合并和分裂的时候都要下传标记 因为树的形态会改变
  3. 交换的时候交换的是整个儿子 意味着序列的形态直接发生变化 交换的是两颗子树 如果只交换信息 那么代表着两个点的信息发生变化
posted @ 2022-03-18 22:36  __iostream  阅读(65)  评论(0)    收藏  举报