TYVJ 1729 - 文艺平衡树

描述 Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
输入格式 InputFormat
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n
输出格式 OutputFormat
输出一行n个数字,表示原始序列经过m次变换后的结果
样例输入 SampleInput 
5 3
1 3
1 3
1 4
样例输出 SampleOutput 
4 3 2 1 5 
数据范围和注释 Hint
n,m<=100000 

题解

蒟蒻我第一次打splay,代码丑,不过还算是懂了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define MAXN 100002 
using namespace std;
int n,m,loc[MAXN],root,size;
int fa[MAXN],son[MAXN],tr[MAXN][2],turn[MAXN];
//fa:记录father。 son:记录节点数  tr:tree,0为左儿子,1为右儿子,turn:翻转标记 
void up(int w)
{
	int l=tr[w][0],r=tr[w][1];
	son[w]=son[l]+son[r]+1;
}
void build(int l,int r,int f/*father*/)
{
	if(l>r) return;
	int p,last,mid;
	if(l==r)
	   {p=loc[l]; last=loc[f];
		fa[p]=last; son[p]=1;
	    if(l<f) tr[last][0]=p;
	    else tr[last][1]=p;
	   }
	mid=(l+r)>>1;
	p=loc[mid]; last=loc[f];
	build(l,mid-1,mid); build(mid+1,r,mid);
	fa[p]=last;  up(mid);
	if(mid<f) tr[last][0]=p;
	else tr[last][1]=p;
}
void init()
{
	scanf("%d%d",&n,&m);
	int i;
	for(i=1;i<=n+2;i++) loc[i]=++size;//为了防止数组超界。 
	build(1,n+2,0); root=(n+3)>>1; //(n+2+1)>>1;
}
//----------------------------------------------以上为预处理。
void down(int w)//标记下传
{
	int l=tr[w][0],r=tr[w][1];
	if(turn[w])
	   {swap(tr[w][0],tr[w][1]); //这里不能用l、r代替 
	    turn[l]^=1; turn[r]^=1;
	    turn[w]=0;
	   }
} 
int find(int w,int x)//找树中标记,与treap类似 
{
	down(w);
	int l=tr[w][0],r=tr[w][1];
	if(son[l]+1==x) return w;
	else if(son[l]>=x) return find(l,x);
	else return find(r,x-son[l]-1); 
} 
void rotate(int x,int &w)//旋转--具体步骤 
{
	int y=fa[x],z=fa[y],l,r;
	if(tr[y][0]==x) l=0;
	else l=1;
	r=l^1;
	if(y==w) w=x;
	else
	   {if(tr[z][0]==y) tr[z][0]=x;
	    else tr[z][1]=x;
	   }
	fa[x]=z; fa[y]=x; fa[tr[x][r]]=y;
	tr[y][l]=tr[x][r]; tr[x][r]=y;
	up(y); up(x);
}
void splay(int x,int &w)//旋转--大步骤 
{
	while(x!=w)
	   {int y=fa[x],z=fa[y];
	    if(y!=w)
	       {if((tr[y][0]==x)^(tr[z][0]==y)) rotate(x,w);
		    else rotate(y,w);
		   }
		rotate(x,w);
	   }
}
void overturn(int l,int r) //翻转操作 
{
	int x=find(root,l),y=find(root,r+2);//为了方便,splay中所有元素标号+1,如1号元素标号为2
	splay(x,root); splay(y,tr[x][1]);
	int z=tr[y][0];
	turn[z]^=1; 
} 
void work()
{
	int i,l,r;
	for(i=1;i<=m;i++)
	   {scanf("%d%d",&l,&r);
	    overturn(l,r);
	   }
	for(int i=2;i<=n+1;i++)
	   printf("%d ",find(root,i)-1);
} 
int main()
{
	init(); work();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值