zoukankan      html  css  js  c++  java
  • [BZOJ 3223] 文艺平衡树

    Link:

    BZOJ 3223 传送门

    Solution:

    $Splay$对序列操作的模板题

    核心思想就是将$L-1$移到根,$R+1$移至$L-1$的下方,从而约束出区间$[L,R]$进行操作

    对于此题仅要求将区间翻转,因此只要将左右子树交换即可

    但同时类似于线段树要打上懒惰标记来保证复杂度,每次查询第$K$大时下放标记

    Tips:

    1、对于此题不再关心每个数的权值,而只关心其在序列中的编号

    而这个节点的排名($sz[ch[x][0]]+1$)就是其当前的序号

    2、为了处理$[1,n]$等边界情况,新增$1,n+2$作为真·边界

    3、一开始可以通过分治直接建树,不用一个个$insert$,但要将$f[rt]$置为$0$!!!

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAXN=1e5+10;
    int n,m,rt,l,r,sz[MAXN],f[MAXN],ch[MAXN][2],tag[MAXN];
    
    void pushup(int x)
    {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
    
    void pushdown(int x)
    {
        if(!tag[x]) return;
        tag[ch[x][1]]^=1;tag[ch[x][0]]^=1;
        swap(ch[x][0],ch[x][1]);tag[x]=0;
    }
    
    void Build(int l,int r,int anc)
    {
        if(l>r) return;
        int mid=(l+r)/2;
        if(mid<anc) ch[anc][0]=mid;
        else ch[anc][1]=mid;
        sz[mid]=1;f[mid]=anc;
        if(l==r) return;
        
        Build(l,mid-1,mid);Build(mid+1,r,mid);
        pushup(mid);
    }
    
    void Print(int x)
    {
        pushdown(x);
        if(ch[x][0]) Print(ch[x][0]);
        if(x>1&&x<n+2) printf("%d ",x-1);
        if(ch[x][1]) Print(ch[x][1]);
    }
    
    void Rotate(int x)
    {
        int y=f[x],z=f[y],k=(ch[y][1]==x);
        ch[z][ch[z][1]==y]=x;f[x]=z;
        ch[y][k]=ch[x][k^1];f[ch[x][k^1]]=y;
        ch[x][k^1]=y;f[y]=x;
        pushup(x);pushup(y);
    }
    
    void Splay(int x,int up)
    {
        while(f[x]!=up)
        {
            int y=f[x],z=f[y];
            if(z!=up) (ch[y][1]==x)^(ch[z][1]==y)?Rotate(x):Rotate(y);
            Rotate(x);
        }
        if(!up) rt=x;
    }
    
    int Kth(int x)
    {
        int k=rt;
        while(true)
        {
            pushdown(k);
            if(x==sz[ch[k][0]]+1) return k;
            else if(sz[ch[k][0]]>=x) k=ch[k][0];
            else x-=sz[ch[k][0]]+1,k=ch[k][1];
        }
    }
    
    void Reverse(int l,int r)
    {
        int x=Kth(l),y=Kth(r+2);
        Splay(x,0);Splay(y,x);
        tag[ch[ch[rt][1]][0]]^=1;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        rt=(n+3)/2;Build(1,n+2,rt);f[rt]=0;
        
        for(int i=1;i<=m;i++)
            scanf("%d%d",&l,&r),Reverse(l,r);
        Print(rt);
        return 0;
    }
  • 相关阅读:
    michael的沟通秘籍
    panels能否包含views_block ////// panels -- content pane 参数传递
    Unity动画
    DoTween动画插件学习
    C#委托的进一步学习
    阶段学习总结-坦克大战(2D)案例
    学习总结
    阶段学习总结-见缝插针案例
    阶段学习总结-坦克大战案例
    碰撞检测和触发检测
  • 原文地址:https://www.cnblogs.com/newera/p/9338199.html
Copyright © 2011-2022 走看看