UVA 11922 Permutation Transformer 伸展树(模板)

题意:有个原始数列1,2,3..n,有m个指令,每个指令(a,b)表示取出第a~b个元素,翻转后添加到排列的尾部。

思路:白书上的例题,学过splay树后就不怎么难了,先贴个模板,需要注意的是得多加个0在原始数列前面,方便分裂序列。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
struct Node
{
	Node *ch[2];
	int v,s,flip;
	Node(int v):v(v){ch[0]=ch[1]=NULL,s=1,flip=0;}
	int cmp(int x)
	{
		int t=(ch[0]==NULL)?0:ch[0]->s;
		if(t>=x)
		return 0;
		else if(t+1==x)
		return -1;
		return 1;
	}
	void maintain()
	{
		s=1;
		if(ch[0]!=NULL)s+=ch[0]->s;
		if(ch[1]!=NULL)s+=ch[1]->s;
	}
	void pushdown()
	{
		if(flip)
		{
			flip=0;
			swap(ch[0],ch[1]);
			if(ch[0]!=NULL)
			ch[0]->flip^=1;
			if(ch[1]!=NULL)
			ch[1]->flip^=1;
		}
	}
};
void rotate(Node* &o,int d)
{
	Node *k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
	o->maintain();k->maintain();o=k;
}
void splay(Node* &o,int k)
{
	o->pushdown();
	int d=o->cmp(k);
	if(d==1) 
	{
		if(o->ch[0]!=NULL)k-=o->ch[0]->s;	
		k--;
	}
	if(d!=-1)
	{
		Node* p=o->ch[d];p->pushdown();
		int k2=k,d2=p->cmp(k);
		if(d2==1)
		{
			if(p->ch[0]!=NULL)
			k2-=p->ch[0]->s;
			k2--;
		}
		if(d2!=-1)
		{
			splay(p->ch[d2],k2); 
			if(d==d2)rotate(o,d^1);else rotate(o->ch[d],d);
		}
		rotate(o,d^1);
	}
}
Node* merge(Node* left,Node* right)
{
	splay(left,left->s);
	left->ch[1]=right;
	left->maintain();
	return left;
}
void split(Node *o,int k,Node* &left,Node* &right)
{
	splay(o,k);
	left=o;
	right=o->ch[1];
	o->ch[1]=NULL;
	left->maintain();
}
void build(Node* &o,int l,int r)
{
	int m=(l+r)/2;
	o=new Node(m);
	if(l<m)
	build(o->ch[0],l,m-1);
	if(r>m)
	build(o->ch[1],m+1,r);
	o->maintain();
}
int n,m;
Node *root;
void dfs(Node *o)
{
	o->pushdown();
	if(o->ch[0]!=NULL)
	dfs(o->ch[0]);
	if(o->v!=0&&o->v!=n+1)
	printf("%d\n",o->v);
	if(o->ch[1]!=NULL)
	dfs(o->ch[1]);
}
int main()
{
	scanf("%d%d",&n,&m);
	build(root,0,n);
	while(m--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		Node *left,*mid,*right,*o,*tmp;
		split(root,a,left,o);
		split(o,b-a+1,mid,right);
		mid->flip^=1;
		root=merge(merge(left,right),mid);
	}
	dfs(root);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值