BZOJ3223 文艺平衡树

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

Input

第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n

Output

输出一行n个数字,表示原始序列经过m次变换后的结果

Sample Input

5 3

1 3

1 3

1 4

Sample Output

4 3 2 1 5

HINT

N,M<=100000

Splay裸题。RE了几次,后来发现是建树的问题,最后改了一下建树部分就过了。
Splay的旋转方式真是不习惯呐。。。和普通的平衡树不同,不是通过引用方式修改,而是记录父节点,像链表一样修改。
自己的代码:

#include<cstdio>
#define check if(x->rev)\
    {\
        if(x->s[0]) seija(x->s[0]);\
        if(x->s[1]) seija(x->s[1]);\
        x->rev=0;\
    }
using namespace std;
int n,m,l,r;
struct node
{
    int v,n;
    node *s[2],*fat;
    bool rev;
    node(int v):v(v),n(1),rev(0){s[0]=s[1]=0;}
}*rt;
void build(node* &x,int z,int y)
{
    int mid=(z+y)/2;
    x=new node(mid);
    if(z<=mid-1) {build(x->s[0],z,mid-1);x->s[0]->fat=x;x->n+=x->s[0]->n;}
    if(mid+1<=y) {build(x->s[1],mid+1,y);x->s[1]->fat=x;x->n+=x->s[1]->n;}
}
#define rlt(son,dad) (son==dad->s[0]?0:1)
#define num(x) (x?x->n:0)
#define line(a,b,c) rlt(a,b)==rlt(b,c)
inline void rot(node *son,node *dad)
{
    int k=rlt(son,dad);
    if(dad==rt) rt=son;
    else
    {
        int q=rlt(dad,dad->fat);
        dad->fat->s[q]=son;
    }
    node *x=son->s[1^k];
    int b=son->n;
    son->n=dad->n;dad->n+=num(x)-b;
    son->fat=dad->fat;
    dad->fat=son;
    if(x) x->fat=dad;
    dad->s[k]=x;
    son->s[1^k]=dad;
}
inline void seija(node *x)
{
    x->rev^=1;
    node *y=x->s[0];
    x->s[0]=x->s[1];
    x->s[1]=y;
}
void splay(int k,node* &des)
{
    node *x=rt;
    int y;
    while(1)
    {
        check;
        y=x->n;
        if(x->s[1]) y-=x->s[1]->n;
        if(y==k) break;
        if(k<y) x=x->s[0];
        else
        {
            k-=y;
            x=x->s[1];
        }
    }
    node *z,*w;
    while(x!=des)
    {
        z=x->fat;
        if(z==des) {rot(x,z);break;}
        w=z->fat;
        if(line(x,z,w)) {rot(z,w);rot(x,z);}
        else {rot(x,z);rot(x,w);}
        if(w==des) break;
    }
}
inline void seija()
{
    splay(r+2,rt);
    splay(l,rt->s[0]);
    seija(rt->s[0]->s[1]);
}
void print(node *x)
{
    check;
    if(x->s[0]) print(x->s[0]);
    if(x->v>=1&&x->v<=n) printf("%d ",x->v);
    if(x->s[1]) print(x->s[1]);
}
int main()
{
    scanf("%d%d",&n,&m);
    build(rt,0,n+1);
    for(int i=1;i<=m;i++)
    {   
        scanf("%d%d",&l,&r);
        seija();
    }
    print(rt);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值