zoukankan      html  css  js  c++  java
  • [BZOJ3223]Tyvj 1729 文艺平衡树

    Tyvj 1729 文艺平衡树

    题面

    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(不带区间操作)是按照权值来排序维护二叉查找树的。如果把splay推广到区间操作,我们需要进行一些修改。把一个元素在区间中的下标(即第几个)作为splay树的权值。所以对于这棵splay树的根节点,左边的所有节点在序列中的位置都在根节点之前。这样如果我们需要操作区间([l,r]),我们就先把l-1转到root,再把r+1转到root的右儿子,那么root的右儿子的左子树则是区间([l,r])对应的所有节点。splay树中排名为k的节点则是序列中第k个节点。

    我们可以发现,对于一个子树,子树的根节点的左子树就是在根节点左侧的点,右子树就是在根节点右侧的点。那么我们容易发现,如果把左右子树换一下,然后递归的更新左右子树即可。

    为了优化时间,我们可以像线段树一样打个tag来维护翻转操作。同时Push_Down操作就是下传tag同时交换左右子树。

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define maxn (int)(1e5+1000)
    #define inf (int)(1e9+1000)
    using namespace std;
    int
    val[maxn],tag[maxn],size[maxn],son[maxn][2],fa[maxn],cnt[maxn],s[maxn];
    int n,m,idx,root;
    void push_down(int x){
        if(!tag[x])return;
        if(son[x][0]){
            tag[son[x][0]]^=1;
        }
        if(son[x][1]){
            tag[son[x][1]]^=1;
        }
        tag[x]=0;
        swap(son[x][0],son[x][1]);
        return;
    }
    void push_up(int x){
        size[x]=cnt[x];
        if(son[x][0]){
            size[x]+=size[son[x][0]];
        }
        if(son[x][1]){
            size[x]+=size[son[x][1]];
        }
        return;
    }
    void Down(int x){
        if(!x)return;
        Down(fa[x]);
        push_down(x);
        return;
    }
    void rotate(int x){
        int y=fa[x],z=fa[y],o=(son[y][1]==x);
        son[y][o]=son[x][o^1];
        fa[son[x][o^1]]=y;
    
        son[x][o^1]=y;
        fa[y]=x;
    
        son[z][son[z][1]==y]=x;
        fa[x]=z;
    
        push_up(y);
        push_up(x);
        return;
    }
    void splay(int x,int v=0){
        Down(x);
        for(int y;fa[x]!=v&&fa[x];rotate(x)){
            y=fa[x];
            if(fa[y]==v)continue;
            rotate((son[fa[x]][0]==x)^(son[fa[y]][0]==y)?x:y);
        }
        if(!v)root=x;
    }
    void insert(int x,int a){
        int y=0;
        while(x&&val[x]!=a){
            y=x;
            x=son[x][val[x]<a];
        }
        if(x){
            cnt[x]++;push_up(x);
        }
        else{
            x=++idx;
            val[x]=a;
            tag[x]=son[x][0]=son[x][1]=0;
            cnt[x]=size[x]=1;
            son[y][val[y]<a]=x;
            fa[x]=y;
        }
        splay(x);
        return;
    }
    int kth(int x,int a){
        push_down(x);
        if(size[son[x][0]]>=a){
            return kth(son[x][0],a);
        }
        if(size[son[x][0]]+cnt[x]>=a){
            splay(x);
            return x;
        }
        return kth(son[x][1],a-cnt[x]-size[son[x][0]]);
    }
    void write(int x){
        if(!x)return;
        push_down(x);
        write(son[x][0]);
        if(-1e9<=val[x]&&val[x]<=1e9)printf("%d ",val[x]);
        write(son[x][1]);
        return;
    }
    int main(){
    //	freopen("in","r",stdin);
        scanf("%d%d",&n,&m);
        insert(root,inf);insert(root,-inf);
        for(int i=1;i<=n;i++){insert(root,i);}
        for(int i=1;i<=m;i++){
            int l,r;scanf("%d%d",&l,&r);
            l=kth(root,l+1-1);r=kth(root,r+1+1);
            splay(l);splay(r,root);
            tag[son[son[root][1]][0]]^=1;
            push_down(son[son[root][1]][0]);
        }
        write(root);
        return 0;
    }
    
  • 相关阅读:
    如何在同一窗口打开多个终端并实现快捷键切换
    Django基础八之cookie和session
    jQuery操作cookie
    Django基础九之中间件
    Django基础七之Ajax
    Mac下打开/usr/local目录
    Django基础二之URL路由系统
    json path espressions的语法学习
    如何查看bug属于前端还是后端
    python random生成随机手机号
  • 原文地址:https://www.cnblogs.com/GavinZheng/p/10777379.html
Copyright © 2011-2022 走看看