splay区间翻转及删除区间,平移区间

8 篇文章 0 订阅
6 篇文章 0 订阅

研究了很长时间,花费了一个下午debug,终于调出来了

hdu 3487 play with chain

http://acm.hdu.edu.cn/showproblem.php?pid=3487


两个操作(指针实现)


cut l,r, c把[l,r]剪下来放到剩下序列中第c个后面的位置.

flip l r 把[l,r]翻转(lazy标记,每次交换左右节点)


cut思路:把l-1旋到根,r+1旋到根的右节点,取下这一段;在剩下的序列中找到c,c+1的位置,把c旋到根,c+1旋到右节点,插入。

由平衡树性质易证得是对的(中序遍历恒定)


flip思路:把l-1旋到根,r+1旋到右节点,打上lazy标记。


最后访问的时候需要pushdown.

(中间每次splay,rotate都需要pushdown)


AC代码(调了好久,蒟蒻一枚)

#include<cstdio>
#include<queue>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#define maxn 330000+20
using namespace std;
int n,q;
int cnt=0;
struct node
{
	node *f;
	node *ch[2];
	int size;
	int lazy;
	int id;
}S[maxn];
node *root;
void pushdown(node *u)
{
	if((!u->lazy)||(u==NULL))return ;
	if(u->ch[0]!=NULL)u->ch[0]->lazy^=1;
	if(u->ch[1]!=NULL)u->ch[1]->lazy^=1;
	node *y=u->ch[0];
	u->ch[0]=u->ch[1];
	u->ch[1]=y;	
	u->lazy=0; 
}
void pushup(node *u)
{
	u->size=1;
	if(u->ch[0]!=NULL)u->size+=u->ch[0]->size;
	if(u->ch[1]!=NULL)u->size+=u->ch[1]->size;
}
void rotate(node *u)
{
	node *f=u->f;
	if(f==NULL)return ;
	pushdown(u);
	pushdown(f);
	node *ff=f->f;
	int d=u==f->ch[1];
	int dd=0;
	if(ff!=NULL)dd=f==ff->ch[1];
	
	if(u->ch[d^1])u->ch[d^1]->f=f;
	f->ch[d]=u->ch[d^1];
	
	/*int size=u->size;
	u->size=f->size;
	f->size=f->size-size;
	if(u->ch[d^1]!=NULL)f->size+=u->ch[d^1]->size;
	*/
	f->f=u;
	u->ch[d^1]=f;
	
	if(ff!=NULL)ff->ch[dd]=u;
	u->f=ff;
	
	pushup(f);
	pushup(u);
}
void splay(node *u,node *p)
{
	pushdown(u);
	while(u->f!=p)
	{
		node *f=u->f;
		node *ff=f->f;
		if(ff==p)
		{
			rotate(u);
			break;
		}
		int d=u==f->ch[1];
		int dd=f==ff->ch[1];
		if(d==dd)rotate(f);
		else rotate(u);
		rotate(u);
	}
	pushup(u);
	if(p==NULL)root=u;
}
void insert(int id)
{
	if(root==NULL)
	{
		node *y=&S[++cnt];
		y->id=id;
		y->size=1;
		y->ch[0]=NULL;
		y->ch[1]=NULL;
		y->f=NULL;
		y->lazy=0;
		root=y;
		return ;
	}
	node *u=root;
	node *y;
	while(1)
	{
		u->size++;
		if(id<u->id)
		{
			//左边
			if(u->ch[0]!=NULL)u=u->ch[0];
			else
			{
				y=&S[++cnt];
	        	y->id=id;
		        y->size=1;
		        y->ch[0]=NULL;
				y->ch[1]=NULL;
		        y->f=u;
		        u->ch[0]=y;
		        y->lazy=0;
		        break;
			} 
		}
		else
		{
			if(u->ch[1]!=NULL)u=u->ch[1];
			else
			{
				y=&S[++cnt];
	        	y->id=id;
		        y->size=1;
		        y->ch[0]=NULL;
				y->ch[1]=NULL;
		        y->f=u;
		        u->ch[1]=y;
		        y->lazy=0;
		        break;
			}
		}
	}
	splay(y,NULL);
}
char s[10];
node *find (int x)
{
	node *u=root;
	while(1)
	{
		int xx=1;
		if(u->ch[0]!=NULL)xx+=u->ch[0]->size;
		if(xx==x)return u;
		if(x<xx)u=u->ch[0];
		else 
		{
			x-=xx;
			u=u->ch[1];
		}
	}
}
void cut(int l,int r,int c)
{
	node *x=find(l);
	node *y=find(r+2);
	splay(x,NULL);
	splay(y,root);
	node *u=root->ch[1]->ch[0];
	/*root->size-=u->size;
	root->ch[1]->size-=u->size;
	*/
	root->ch[1]->ch[0]=NULL;
	pushup(root->ch[1]);
	pushup(root);
	//u->f=NULL;
	node *yy=find(c+1);
	splay(yy,NULL);
	node *xx=find(c+2);
	splay(xx,root);
	//插入 
	root->ch[1]->ch[0]=u;
	u->f=root->ch[1];
	//root->ch[1]->size+=u->size;
	//root->size+=u->size;
	pushup(root->ch[1]);
	pushup(root);
}
void flip(int l,int r)
{
	node *x=find(l);
	node *y=find(r+2);
	splay(x,NULL);
	splay(y,root);
	node *u=root->ch[1]->ch[0];
	u->lazy^=1; 
}
void dfs(node *u)
{
	//printf("debug :  %d  %d\n",u->size,u->id);
	pushdown(u);
	if(u->ch[0])dfs(u->ch[0]);
	if(u->id!=0&&u->id!=n+1)printf("%d ",u->id);	
	if(u->ch[1])dfs(u->ch[1]); 
}
int main()
{
	freopen("hoho.txt","r",stdin);
	while(scanf("%d%d",&n,&q)!=EOF&&!(n<0&&q<0))
	{
		cnt=0;
		root=NULL;
		for(int i=0;i<=n+1;i++)insert(i);		
		for(int i=1;i<=q;i++)
		{
			scanf("%s",s);
			if(s[0]=='C')
			{
				int a,b,c;
				scanf("%d%d%d",&a,&b,&c);
				cut(a,b,c);
			}
			else
			{
				int a,b;
				scanf("%d%d",&a,&b);
				flip(a,b);
			}
		}
		dfs(root);
		printf("\n");
	}
	
	return 0;
}

注意控制格式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值