hdu3487:Play with Chain (splay)

本文介绍了一道关于维护序列并支持特定操作的算法题目,通过使用Splay树(伸展树)来高效地实现cut和flip操作。cut操作涉及序列的切割与重组,而flip则需要翻转序列中的一部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3487

题目大意:要你维护一个序列,支持两种操作:cut a b c,把原序列的[a,b]这段剪切下来,接到新序列的第c位后面;flip a b,翻转[a,b]。

分析:没什么好说的,splay裸题一道,一次cut操作意味着一次分离与一次合并,flip的话懒惰标记就好了。

CODE:

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;

const int maxn=300100;

struct Tnode
{
	int val,Size;
	bool flip;
	Tnode *son[2],*fa;
	int Lsize() { return son[0]?son[0]->Size:0; }
	void Get_size() { Size=Lsize()+(son[1]?son[1]->Size:0)+1; }
	int Get_d() { return fa->son[1]==this; }
	void Connect(Tnode *P,int d) { (son[d]=P)->fa=this; }
	void Push_down()
	{
		if (flip)
		{
			swap(son[0],son[1]);
			if (son[0]) son[0]->flip^=1;
			if (son[1]) son[1]->flip^=1;
			flip=0;
		}
	}
} tree[maxn];
Tnode *Root;
int cur;

char op[15];
int n,m;

Tnode *Build(Tnode *F,int L,int R)
{
	if (L>R) return NULL;
	Tnode *P=&tree[++cur];
	int mid=(L+R)>>1;
	P->val=mid;
	P->fa=F;
	P->flip=false;
	P->son[0]=Build(P,L,mid-1);
	P->son[1]=Build(P,mid+1,R);
	P->Get_size();
	return P;
}

void Zig(Tnode *P,Tnode *&tag)
{
	Tnode *F=P->fa;
	int d=P->Get_d();
	if (P->son[!d]) F->Connect(P->son[!d],d);
	else F->son[d]=NULL;
	if (F!=tag) F->fa->Connect(P,F->Get_d());
	else
	{
		P->fa=F->fa;
		tag=P;
	}
	P->Connect(F,!d);
	F->Get_size();
}

void Splay(Tnode *P,Tnode *&tag)
{
	Tnode *F;
	while (P!=tag)
	{
		F=P->fa;
		if (F!=tag) ( P->Get_d()^F->Get_d() )? Zig(P,tag):Zig(F,tag);
		Zig(P,tag);
	}
	P->Get_size();
}

void Work(Tnode *P,int rank,Tnode *&tag)
{
	P->Push_down();
	int ls=P->Lsize()+1;
	if (rank<ls) Work(P->son[0],rank,tag);
	if (rank==ls) Splay(P,tag);
	if (rank>ls) Work(P->son[1],rank-ls,tag);
}

void Print(Tnode *P)
{
	if (!P) return;
	P->Push_down();
	Print(P->son[0]);
	if ( P->val && P->val!=n+1 )
	{
		printf("%d",P->val);
		if (P!=Root) printf(" ");
	}
	Print(P->son[1]);
}

int main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	
	scanf("%d%d",&n,&m);
	while ( n>0 && m>=0 )
	{
		cur=-1;
		Root=Build(NULL,0,n+1);
		
		for (int i=1; i<=m; i++)
		{
			scanf("%s",&op);
			if (op[0]=='C')
			{
				int a,b,c;
				scanf("%d%d%d",&a,&b,&c);
				
				Work(Root,a,Root);
				Work(Root,b+2,Root->son[1]);
				Tnode *tag=Root->son[1]->son[0];
				Root->son[1]->son[0]=NULL;
				Root->son[1]->Get_size();
				Root->Get_size();
				
				Work(Root,c+1,Root);
				Work(Root,c+2,Root->son[1]);
				Root->son[1]->Connect(tag,0);
				Root->son[1]->Get_size();
				Root->Get_size();
			}
			
			if (op[0]=='F')
			{
				int L,R;
				scanf("%d%d",&L,&R);
				Work(Root,L,Root);
				Work(Root,R+2,Root->son[1]);
				Root->son[1]->son[0]->flip^=1;
			}
		}
		
		Work(Root,Root->Size-1,Root);
		Print(Root);
		printf("\n");
		scanf("%d%d",&n,&m);
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值