JDOJ-2184: 文艺平衡树

[文章目录]

Description

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

依靠大爷的代码爽爽的A了一道splay的题。(其实很崩溃233)

在节点上加标记,然后下传就好了(说的像是很简单的样子)实际上指针版好难写的+好难理解的+好难想的。

woc 格式还要求没有结尾空格,导致我多开了一个数组

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int k1,k2;
int cnt,a[100010];
struct node
{
    int val,size;bool tur;
    node *fa,*ls,*rs;//结构体指针
    node();//结构体初始化函数
    void push_down();//结构体函数
    void push_up();
    void reverse();
}*null=new node(),*root;//null为一个指针,下面将所有的空指针(fa,ls,rs)都指向它
int n,m;
node :: node()
{
    fa=ls=rs=null;
    tur=false;val=-1;
    size=null?1:0;//null?是在null为空时size为0,非空时为1。
    //(也就是说只有null的size为0)%%%POPOQQQ 姐姐的高级写法
}
void node :: reverse()//区间反转
{
    swap(ls,rs);
    tur^=1;
}
void node :: push_down()//下传标记
{
    if(tur)
    {
        ls->reverse();
        rs->reverse();
        tur=0;
    }
}
void node :: push_up()//由于zig+zag,所以要更新size值
{
    size=ls->size+rs->size+1;
}
node* build(int l,int r)//建树
{
    int mid=(l+r)>>1;
    if(l>r) return null;//将所有的边界都指向null
    node *re=new node();//开一个新的结构体指针
    re->ls=build(l,mid-1);
    re->rs=build(mid+1,r);
    re->val=mid;
    re->ls->fa=re;
    re->rs->fa=re;
    return re->push_up(),re;//计算size
}
void initialize()//初始化
{
    root=new node();
    root->rs=new node();
    root->rs->ls=build(1,n);//在根与根的rs之间建树
    root->rs->ls->fa=root->rs;
    root->rs->fa=root;
    root->rs->push_up();
    root->push_up();
}

void zig(node *x) //超多小细节的右旋
{  
    node *y=x->fa; 
    y->ls=x->rs;  
    x->rs->fa=y;  
    x->rs=y;  
    x->fa=y->fa;  
    if(y==y->fa->ls)  
        y->fa->ls=x;  
    else if(y==y->fa->rs)  
        y->fa->rs=x;  
    y->fa=x; 
    y->push_up();//注意顺序
    x->push_up();
    if(y==root)  
        root=x;  
}  
void zag(node *x)  //左旋
{  
    node *y=x->fa;
    y->rs=x->ls;  
    x->ls->fa=y;  
    x->ls=y;  
    x->fa=y->fa;  
    if(y==y->fa->ls)  
        y->fa->ls=x;  
    else if(y==y->fa->rs)  
        y->fa->rs=x;  
    y->fa=x; 
    y->push_up();//
    x->push_up();
    if(y==root)
        root=x;  
} 
void splay(node *x,node *tar)
{
    while(1)//将x旋转直到fa为tar
    {
        node *y=x->fa,*z=y->fa;
        if(y==tar) break;
        if(z==tar)
        {
            if(x==y->ls) zig(x);
            else zag(x);
            break;
        }
        if(x==y->ls)
        {
            if(y==z->ls) zig(y);
            zig(x);
        }
        else
        {
            if(y==z->rs) zag(y);
            zag(x);
        }
    }
}
void find(node *x,int y,node *z)
{
    while(1)//通过size找到x
    {
        int temp=x->ls->size;
        x->push_down();
        if(y<=temp) x=x->ls;
        else
        {
            y-=temp;
            if(y==1) break;
            y--;
            x=x->rs;
        }
    }
    splay(x,z);//play!!!
}
void dfs(node *x)//中序遍历
{
    if(x==null) return ;
    x->push_down();//下传标记
    dfs(x->ls);
    a[++cnt]=x->val;
    dfs(x->rs);
}
int main()
{
    scanf("%d%d",&n,&m);
    initialize();//
    while(m--)
    {
        scanf("%d%d",&k1,&k2);
        find(root,k1,null);//因为根的fa为null,并且splay是当x的fa满足时退出,所以这样写。
        /*由于find()里是靠size也就是排名找到位置的,
        并且build时是开区间,
        所以将起点的上一名提到根,终点下一名提到跟的rs
        */
        find(root,k2+2,root);//将终点提升直到fa为root
        root->rs->ls->reverse();//标记
    }
    find(root,1,null);//将整个区间提到上面
    find(root,n+2,root);
    dfs(root->rs->ls);
    for(int i=1;i<n;i++) printf("%d ",a[i]);
        printf("%d",a[n]);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注