HDU3487 Play with Chain(Splay)

有一个数列(1,2,3......,n),有两种操作

CUT a b c 把数列[a,b]截去,插入截去后的数列的c号元素后面

FLIP a b 把数列[a,b]翻转

splay水过

#include<cstdio>
#include<cstring>
#define MAXN 300010
int ans[MAXN],cnt,n,m,root,tot,ch[MAXN][2],sz[MAXN],fa[MAXN],v[MAXN],a[MAXN],rev[MAXN];
char ops[10];
inline void Swap(int &a,int &b)
{int c = a; a = b; b = c;}
void pushup(int x)
{
	sz[x] = sz[ch[x][0]]+sz[ch[x][1]]+1;
}
void pushdown(int x)
{
	if(rev[x])
	{
		rev[ch[x][0]] ^= 1;
		rev[ch[x][1]] ^= 1;
		Swap(ch[x][0],ch[x][1]);
		rev[x] = 0;
	}
}
void rotate(int x)
{
	int y = fa[x],z = fa[y],f = (ch[y][1]==x);
	ch[y][f] = ch[x][!f];
	if(ch[y][f]) fa[ch[y][f]] = y;
	ch[x][!f] = y,fa[y] = x;
	fa[x] = z;
	if(z) ch[z][ch[z][1]==y] = x;
	pushup(y);
}
void splay(int x,int goal)
{
	for(int y; (y=fa[x]) != goal; rotate(x))
	{
		int z = fa[y];
		if(z != goal)
		{
			if((ch[z][0]==y) == (ch[y][0]==x)) rotate(y);
			else rotate(x);
		}
	}
	if(!goal) root = x;
	pushup(x);
}
void New(int &x,int val)
{
	x = ++tot;
	v[x] = val;
	sz[x] = 1;
}
void build_tree(int &x,int L,int R,int F)
{
	int mid = (L+R)/2;
	New(x,a[mid]);
	fa[x] = F;
	if(L < mid) build_tree(ch[x][0],L,mid-1,x);
	if(R > mid) build_tree(ch[x][1],mid+1,R,x);
	pushup(x);
}
void rotateto(int k,int goal)
{
	int x = root;
	while(1)
	{
		pushdown(x);
		if(k > sz[ch[x][0]]+1) k -= sz[ch[x][0]]+1,x = ch[x][1];
		else if(k < sz[ch[x][0]]+1) x = ch[x][0];
		else break;
	}
	splay(x,goal);
}
void reverse(int L,int R)
{
	rotateto(L,0);
	rotateto(R+2,root);
	int u = ch[ch[root][1]][0];
	rev[u] ^= 1;
}
void move(int L,int R,int x)
{
	rotateto(L,0);
	rotateto(R+2,root);
	int u = ch[ch[root][1]][0];
	ch[ch[root][1]][0] = 0;
	pushup(ch[root][1]);
	pushup(root);
	
	rotateto(x+1,0);//这里被坑了,给出的就是剩下数当中第x号元素,不用减去sz[u]
	rotateto(x+2,root);
	ch[ch[root][1]][0] = u;
	fa[u] = ch[root][1];
	pushup(ch[root][1]);
	pushup(root);
}
void Print(int x)
{
	if(x == 0) return;
	pushdown(x);
	Print(ch[x][0]);
	if(v[x] != 0)
	ans[++cnt] = v[x];
	Print(ch[x][1]);
}
void init()
{
	root = tot = cnt = 0;
	memset(sz,0,sizeof sz);
	memset(rev,0,sizeof rev);
	memset(ch,0,sizeof ch);
	memset(fa,0,sizeof fa);
}
int main()
{
	int x,y,z;
	while(scanf("%d%d",&n,&m) != EOF)
	{
		init();
		for(int i = 1; i <= n; i++) a[i] = i;
		build_tree(root,0,n+1,0);//这里多插入了0,n+1两个节点
		if(n == m&&n == -1) return 0;
		for(int i = 1; i <= m; i++)
		{
			scanf("%s",ops);
			if(ops[0] == 'C')
			{
				scanf("%d%d%d",&x,&y,&z);
				move(x,y,z);
			}
			else
			{
				scanf("%d%d",&x,&y);
				reverse(x,y);
			}
		}
		Print(root);
		printf("%d",ans[1]);
		for(int i = 2; i <= cnt; i++)
			printf(" %d",ans[i]);
		printf("\n");
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值