Uva11922 Splay

题意:就是splay的区间翻转 然后直接加到序列的末尾

解法:大概是很轻松的 

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

int val[maxn],num[maxn],ch[maxn][2],fa[maxn],root,cnt,rev[maxn];
inline void up(int rt){num[rt]=num[ls]+num[rs]+1;}
inline void down(int rt){
    if(rev[rt]){
        rev[ls]^=1;rev[rs]^=1;swap(ls,rs);rev[rt]=0;
    }
}
inline void node(int rt){fa[rt]=val[rt]=ls=rs=0;num[rt]=1;rev[rt]=0;}
inline 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);
}
inline void splay(int rt,int aim){
    while(fa[rt]!=aim){
        down(rt);
        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;
}
inline void find(int tot,int sub){
    int rt=sub;
    while(1){
        down(rt);
        if(num[ls]+1==tot)break;
        if(num[ls]>=tot)rt=ls;
        else tot-=num[ls]+1,rt=rs;
    }splay(rt,fa[sub]);
}
inline void build(int n){
    cnt=0;node(0);num[0]=0;
    node(++cnt);
    for(int i=2;i<=n+1;++i){
        node(++cnt);fa[i-1]=i;ch[i][0]=i-1;val[i]=i-1;up(i);
    }
    node(++cnt);fa[cnt]=cnt-1;ch[cnt-1][1]=cnt;
    root=cnt-1;up(root);
}
int ans[maxn],sz;
void answer(int rt){
    down(rt);
    if(ls)answer(ls);
    ans[sz++]=val[rt];
    if(rs)answer(rs);
}
int main(){
    int n,m,l,r;
    while(~scanf("%d%d",&n,&m)){
        build(n);
        while(m--){
            scanf("%d%d",&l,&r);
            find(l,root);find(r-l+2,rrs);
            int rt=ch[rrs][0];
//            printf("%d %d\n",val[root],val[rrs]);
            ch[rrs][0]=0;
            rev[rt]^=1;up(rrs);up(root);n-=num[rt];
            find(n+1,root);find(1,rrs);
            fa[rt]=rrs,ch[rrs][0]=rt;
            up(rrs),up(root),n+=num[rt];
        }
        sz=0;
        answer(root);
        for(int i=1;i<=n;++i)printf("%d\n",ans[i]);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值