hdu 3487 Play with Chain(splay tree)

Play with Chain

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1841    Accepted Submission(s): 742


Problem Description
YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n.
At first, the diamonds on the chain is a sequence: 1, 2, 3, …, n.
He will perform two types of operations:
CUT a b c: He will first cut down the chain from the ath diamond to the bth diamond. And then insert it after the cth diamond on the remaining chain.
For example, if n=8, the chain is: 1 2 3 4 5 6 7 8; We perform “CUT 3 5 4”, Then we first cut down 3 4 5, and the remaining chain would be: 1 2 6 7 8. Then we insert “3 4 5” into the chain before 5th diamond, the chain turns out to be: 1 2 6 7 3 4 5 8.

FLIP a b: We first cut down the chain from the ath diamond to the bth diamond. Then reverse the chain and put them back to the original position.
For example, if we perform “FLIP 2 6” on the chain: 1 2 6 7 3 4 5 8. The chain will turn out to be: 1 4 3 7 6 2 5 8

He wants to know what the chain looks like after perform m operations. Could you help him? 
 

Input
There will be multiple test cases in a test data. 
For each test case, the first line contains two numbers: n and m (1≤n, m≤3*100000), indicating the total number of diamonds on the chain and the number of operations respectively.
Then m lines follow, each line contains one operation. The command is like this:
CUT a b c // Means a CUT operation, 1 ≤ a ≤ b ≤ n, 0≤ c ≤ n-(b-a+1).
FLIP a b    // Means a FLIP operation, 1 ≤ a < b ≤ n.
The input ends up with two negative numbers, which should not be processed as a case.
 

Output
For each test case, you should print a line with n numbers. The ith number is the number of the ith diamond on the chain.
 

Sample Input
  
  
8 2 CUT 3 5 4 FLIP 2 6 -1 -1
 

Sample Output
  
  
1 4 3 7 6 2 5 8
 

Source
 

Recommend
zhengfeng
功能:区间剪切,区间插入,区间翻转。。。

CUT   l r c:把第l-1节点splay到root节点,把第r+1节点splay到 ch[root][1]  节点,ch[ch[root][1]][0]为根的子树就是要剪切掉的部分

插入时:把第 c 节点splay到root节点,把第c的后继结点节点splay到 ch[root][1]  节点,此时ch[ch[root][1]][0]为根的子树就为空树,此时就可以把剪切掉的那部分插入到ch[ch[root][1]][0]为根的子树上;

FLIP  l r:翻转操作要用到延迟标记rev(类似于线段树),push_up,push_down,把第l-1节点splay到root节点,把第r+1节点splay到 ch[root][1]  节点,ch[ch[root][1]][0]为根的子树就是要翻转的部分(同剪切);

输出是利用中根遍历;

我的代码:(留着以后当模版用,O(∩_∩)O哈哈~)

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<algorithm>
#define N 500001
#define Key_value ch[ch[root][1]][0]
using namespace std;
int n,q;
int key[N];
int size[N],pre[N],rev[N];
int ch[N][2],tot,root,data[N];
void newnode(int &r,int k,int father){
	r=++tot;
	ch[r][0]=ch[r][1]=0;
	pre[r]=father;
	rev[r]=0;
	key[r]=k;
	size[r]=1;
}
void push_up(int r){
	size[r]=size[ch[r][0]]+size[ch[r][1]]+1;
}
void push_down(int r){
	if(rev[r]){
		swap(ch[r][0],ch[r][1]);
		rev[ch[r][0]]^=1;
		rev[ch[r][1]]^=1;
		rev[r]=0;
	}
}
int flag;
void Inorder(int r)
{
    if(r==0)
    return;
    push_down(r);
    Inorder(ch[r][0]);
    if(key[r]!=-1)
    {
        if(flag)
        {
            printf("%d",key[r]);flag=0;
        }
        else
        printf(" %d",key[r]);
    }
    Inorder(ch[r][1]);
}
void Rotate(int x,int kind){
	int y=pre[x];
	push_down(y);
	push_down(x);
	ch[y][!kind]=ch[x][kind];
	pre[ch[x][kind]]=y;
	if(pre[y])
		ch[pre[y]][ch[pre[y]][1]==y]=x;
	pre[x]=pre[y];
	ch[x][kind]=y;
	pre[y]=x;
	push_up(y);
}
void Splay(int r,int goal){
	push_down(r);
	while(pre[r]!=goal){
		if(pre[pre[r]]==goal)
			Rotate(r,ch[pre[r]][0]==r);
		else{
			int y=pre[r];
			int kind=(ch[pre[y]][0]==y);
			if(ch[y][kind]==r){
				Rotate(r,!kind);
				Rotate(r,kind);
			}
			else{
				Rotate(y,kind);
				Rotate(r,kind);
			}
		}
	}
	push_up(r);
	if(goal==0) root=r;
}
void RotateTo(int k,int goal) {
    int r=root;
    push_down(r);
    while(size[ch[r][0]]!=k){
        if(k<size[ch[r][0]]){
            r=ch[r][0];
        } else {
            k-=(size[ch[r][0]]+1);
            r=ch[r][1];
        }
        push_down(r);
    }
    Splay(r,goal);
}
int Get_Kth(int r,int k){
	push_down(r);
	int t=size[ch[r][0]]+1;
	if(t==k)
		return r;
	if(t>k)
		return Get_Kth(ch[r][0],k);
	else
		return Get_Kth(ch[r][1],k-t);
}
int Get_Min(int r){
	push_down(r);
	while(ch[r][0]){
		r=ch[r][0];
		push_down(r);
	}
	return r;
}
int Get_Max(int r){
	push_down(r);
	while(ch[r][1]){
		r=ch[r][1];
		push_down(r);
	}
	return r;
}
void Reversal(int l,int r){
	RotateTo(l-1,0);
	RotateTo(r+1,root);
	rev[Key_value]^=1;
}
void build(int &r,int L,int R,int fa)
{
    if(L>R)
    return;
    int mid=(L+R)/2;
    newnode(r,data[mid],fa);
    build(ch[r][0],L,mid-1,r);
    build(ch[r][1],mid+1,R,r);
    push_up(r);
}
void Init()
{
    tot=root=0;
    ch[0][0]=ch[0][1]=pre[0]=size[0]=0;
    newnode(root,-1,0);
    newnode(ch[root][1],-1,root);
    //size[root]=2;
    for(int i=1;i<=n;i++)
    data[i]=i;
    build(Key_value,1,n,ch[root][1]);
    push_up(ch[root][1]);
    push_up(root);
}
void ins(int c,int r)
{
    RotateTo(c,0);
  int x=Get_Min(ch[root][1]);
  Splay(x,root);
  Key_value=r;
  pre[Key_value]=ch[root][1];
}
int Delete(int l,int r)
{
	RotateTo(l-1,0);
	RotateTo(r+1,root);
	int kk;
	kk=Key_value;
	pre[Key_value]=0;
	Key_value=0;
	push_up(ch[root][1]);
	push_up(root);
	return kk;
}
char str[10];
int main(){
	//freopen("editor1.in","r",stdin);
	while(scanf("%d%d",&n,&q)!=EOF){
	    if(n==-1&&q==-1)
	    break;
		Init();
		int k,l,r,c;
		while(q--){
			scanf("%s",str);
			if(str[0]=='C'){
				scanf("%d%d%d",&l,&r,&c);
				getchar();
				k=Delete(l,r);
				ins(c,k);
			}
			else if(str[0]=='F'){
				scanf("%d%d",&l,&r);
				getchar();
				Reversal(l,r);
			}
		}
		flag=1;
       Inorder(root);
       printf("\n");
    }
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值