hdu3487 Splay

题意:给定数字的序列 操作是翻转序列中的一段数字 或者是 将其中一段数字剪切下来 然后粘贴在剪切完的数组的一个数之后

解法:splay区间翻转,区间剪切

这个旋转操作ms有点花样的

#include<cstdio>
#include<iostream>
using namespace std;
#define maxn 333333
#define rls ch[root][0]
#define rrs ch[root][1]
#define ls ch[rt][0]
#define rs ch[rt][1]

int ch[maxn][2],num[maxn],fa[maxn],rev[maxn];
int n,m,root,cnt;
void up(int rt){
    num[rt]=num[ls]+num[rs]+1;
}
void down(int rt){
    swap(ls,rs);
    rev[ls]^=1;rev[rs]^=1;
    rev[rt]=0;
}
void build(){
    memset(ch,0,sizeof ch);
    memset(rev,0,sizeof rev);
    for(int i=1;i<=n+2;++i)
        fa[i]=i+1,num[i]=i,ch[i][0]=i-1;
    root=n+2;fa[n+2]=0;
    cnt=0;
}
void rot(int rt){
    int f=fa[rt],side=(ch[f][1]==rt),&ll=ch[rt][!side];
    fa[ll]=f;ch[f][side]=ll;
    fa[rt]=fa[f];ch[fa[f]][ch[fa[f]][1]==f]=rt;
    fa[f]=rt,ch[rt][!side]=f;
    up(f),up(rt);
}
void splay(int rt,int aim){
    while(fa[rt]!=aim){
        int f=fa[rt],ff=fa[f];
        if(ff==aim)rot(rt);
        else if((ch[f][1]==rt)==(ch[ff][1]==f))rot(f),rot(rt);
        else rot(rt),rot(rt);
    }if(!aim)root=rt;
}
void find(int tot,int sub){
    int rt=sub;
    while(1){
        if(rev[rt])down(rt);
        if(num[ls]==tot-1)break;
        if(num[ls]>=tot)rt=ls;
        else tot-=num[ls]+1,rt=rs;
    }
    splay(rt,fa[sub]);
}
void flip(int l,int r){
    find(l,root);
    find(r-l+2,rrs);
    rev[ch[rrs][0]]^=1;
}
void cut(int l,int r,int pos){
    find(l,root);
    find(r-l+2,rrs);
    int rl=ch[rrs][0];
    ch[rrs][0]=0;up(rrs),up(root);
    find(pos+2,root);
    find(pos+1,rls);
    ch[rls][1]=rl;fa[rl]=rls;
    up(rls),up(root);
}
int ans[maxn];
void print(int rt){
    if(rev[rt])down(rt);
    if(ls)print(ls);
    ans[++cnt]=rt;
    if(rs)print(rs);
}
int a,b,c;
int main(){
    while(~scanf("%d%d",&n,&m)){
        if(n==-1&&m==-1)break;
        build();
        char s[111];
        while(m--){
            scanf("%s",s);
            if(*s=='F'){
                scanf("%d%d",&a,&b);
                flip(a,b);
            }else if(*s=='C'){
                scanf("%d%d%d",&a,&b,&c);
                cut(a,b,c);
            }
        }
        print(root);
        for(int i=2;i<cnt;++i)printf(i==2?"%d":" %d",ans[i]-1);
        printf("\n");
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值