【BZOJ 3223】文艺平衡树

【题目】

传送门

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 1,翻转区间是 [ 2 , 4 ] 的话,结果是 5 2 3 4 1

Input

第一行为 n , m

n 表示初始序列有 n 个数,这个序列依次是 ( 1 , 2 …… , n-1 , n ),m 表示翻转操作次数

接下来 m 行每行两个数 [ l , r ] 数据保证 1 ≤ l  ≤ r  ≤ n

Output

输出一行 n 个数字,表示原始序列经过 m 次变换后的结果 

Sample Input

5 3
1 3
1 3
1 4

Sample Output

4 3 2 1 5

HINT

N,M ≤ 100000

【分析】

Splay 裸题,由于我是初学,一个简单的错误卡了我好久。。。

大体思路就是以中间的为根,左右两边递归建树(以数组下标来建),然后对于每组询问 l,r,都把 l-1 转到根,r+1 转到根的右子树,这样 r+1 的左子树就是 [ l , r ] 间的所有数,对它左子树的根打一个翻转标记(和线段树的差不多),每次若发现要翻转,就下传标记,并翻转左右两子树,最后中序遍历就是答案

还有一个玄学问题:我们要建立虚点 0 和 n +1,不加会过不了,我也不知道为什么

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500005
#define lc(x) son[x][0]
#define rc(x) son[x][1]
using namespace std;
int n,m,t=0,root=0;
int fa[N],num[N],val[N],lazy[N],size[N],son[N][2];
int Get(int x)
{
	return x==rc(fa[x]);
}
void pushup(int x)
{
	size[x]=size[lc(x)]+size[rc(x)]+num[x];
}
void pushdown(int root)
{
	if(!lazy[root])  return;
	swap(lc(root),rc(root));
	lazy[lc(root)]^=1;
	lazy[rc(root)]^=1;
	lazy[root]=0;
}
void rotate(int &root,int x)
{
	int y=fa[x],z=fa[y];
	int r1=Get(x),r2=Get(y);
	pushdown(y),pushdown(x);
	if(y==root)  root=x;
	else  son[z][r2]=x;
	son[y][r1]=son[x][r1^1],fa[son[x][r1^1]]=y;
	son[x][r1^1]=y,fa[y]=x,fa[x]=z;
	pushup(y),pushup(x);
}
void splay(int &root,int x)
{
	int y=fa[x],z=fa[y];
	while(x!=root)
	{
		if(y!=root)
		{
			if(Get(x)==Get(y))  rotate(root,y);
			else  rotate(root,x);
		}
		rotate(root,x);
		y=fa[x],z=fa[y];
	}
}
int newnode(int x)
{
	lazy[++t]=0;
	size[t]=num[t]=1;
	val[t]=x,lc(t)=rc(t)=0;
	return t;
}
int build(int l,int r,int father)
{
	if(l>r)  return 0;
	int mid=(l+r)>>1;
	int x=newnode(mid);
	fa[x]=father;
	lc(x)=build(l,mid-1,x);
	rc(x)=build(mid+1,r,x);
	pushup(x);
	return x;
}
int findkth(int root,int k)
{
	if(k>size[root])  return k=size[root];		
	while(root)
	{	
		pushdown(root);		
		if(k==size[lc(root)]+1)  return root;
		if(k<=size[lc(root)])  root=lc(root);
		else
		{
			k-=size[lc(root)]+num[root];
			root=rc(root);
		}
	}
	return root;
}
void flip(int l,int r)
{
	int x=findkth(root,l);
	int y=findkth(root,r+2);
	splay(root,x),splay(rc(x),y);
	lazy[lc(y)]^=1;
}
void dfs(int root)
{
	if(!root)  return;
	pushdown(root);
	dfs(lc(root));
	if(val[root]>=1&&val[root]<=n)
	  printf("%d ",val[root]);
	dfs(rc(root));
}
int main()
{
	int l,r,i;
	scanf("%d%d",&n,&m);
	root=build(0,n+1,0);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d",&l,&r);
		flip(l,r);
	}
	dfs(root);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/82933601