zoukankan      html  css  js  c++  java
  • 洛谷【模板】文艺平衡树

    题面

    主要新操作是区间翻转,转一个区间[l,r],需要把l-1转到根,把r+1转到l-1(现在的根)的左儿子,使[l,r]独立出来成为r+1的子树

    这样便可以操作了(子树上每个节点都交换左右儿子(想一想)),优化的话打个lazy就是了

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #define rg register
    #define _ (int)1e5+5
    using namespace std;
    int n,m,num,root;
    struct pp
    {
        int son[2],dad,cnt,it,size;
        bool lazy;
    }tr[_];
    inline int read()
    {
        rg int save=0,w=1;rg char q=getchar();
        while(q<'0'||q>'9'){if(q=='-')w=-1;q=getchar();}
        while(q>='0'&&q<='9')save=(save<<3)+(save<<1)+q-'0',q=getchar();
        return save*w;
    }
    inline void pushup(rg int x)
    {
        tr[x].size=tr[tr[x].son[0]].size+tr[tr[x].son[1]].size+tr[x].cnt;
    }/*
    inline void doit(rg int x)
    {
        rg int y=tr[x].dad,z=tr[y].dad;
        rg bool k=tr[y].son[1]==x;
        tr[x].dad=z;
        tr[z].son[tr[z].son[1]==y]=x;
        tr[y].son[k]=tr[x].son[!k];
        tr[tr[y].son[k]].dad=y;
        tr[y].dad=x;
        tr[x].son[!k]=y;
        pushup(y),pushup(x);//记住要更新size!!!
    }*/
    inline void doit(rg int x)//一个结点的旋转
    {
        rg int y=tr[x].dad,z=tr[y].dad;
        rg bool k=tr[y].son[1]==x;
        tr[x].dad=z;
        tr[z].son[tr[z].son[1]==y]=x;
        tr[y].son[k]=tr[x].son[!k];
        tr[tr[y].son[k]].dad=y;
        tr[y].dad=x;
        tr[x].son[!k]=y;
        pushup(y),pushup(x);//记住要更新size!!!
    }
    inline void splay(rg int x,rg int to)//x是坐标
    {
        while(tr[x].dad!=to)
        {
            rg int y=tr[x].dad,z=tr[y].dad;
            if(z!=to)
                (tr[z].son[1]==y)^(tr[y].son[1]==x)?doit(x):doit(y);
            doit(x);
        }
        if(!to)root=x;
    }
    inline void insert(rg int x)//x是值
    {
        rg int now=root,fa=0;
        while(now&&tr[now].it!=x)
            fa=now,now=tr[now].son[x>tr[now].it];
        if(!now)
        {
            now=++num;
            tr[now].it=x,tr[now].cnt=1;
            tr[now].size=1;
            tr[now].dad=fa;
            tr[now].son[0]=tr[now].son[1]=0;
            if(fa)tr[fa].son[x>tr[fa].it]=now;
        }
        else
            tr[now].cnt++;
        splay(now,0);
    }
    inline void down(rg int x)//x是坐标
    {
        rg int l=tr[x].son[0],r=tr[x].son[1];
        tr[l].lazy^=1,tr[r].lazy^=1;
        tr[x].lazy=0;
        tr[x].son[1]=l,tr[x].son[0]=r;
    //    swap(l,r);
    }
    inline int Kth(rg int x)//第x个
    {
        rg int now=root;
        if(x>tr[root].size)return 0;
        while(2233)
        {
            if(tr[now].lazy)down(now);
            rg int front=tr[tr[now].son[0]].size+tr[now].cnt;
            if(x<=tr[tr[now].son[0]].size)now=tr[now].son[0];
            else
                if(x>front)now=tr[now].son[1],x-=front;
                else return now;
        }
    }
    inline void solve(rg int l,rg int r)//把l-1转到根,把r+1转到根的右节点,[l,r]就被放在同一颗子树里了
    {
        rg int ll=Kth(l),rr=Kth(r+2);
        splay(ll,0);splay(rr,ll);
        tr[tr[rr/*tr[root].son[1]*/].son[0]].lazy^=1;
    }
    void putout(rg int now)
    {
        if(tr[now].lazy)
            down(now);
        if(tr[now].son[0])putout(tr[now].son[0]);
        if(tr[now].it!=-2147483647&&tr[now].it!=2147483647)printf("%d ",tr[now].it);
        if(tr[now].son[1])putout(tr[now].son[1]);
    }
    int main()
    {
        n=read(),m=read();
        insert(-2147483647),insert(2147483647);
        rg int i,j;
        for(i=1;i<=n;++i)insert(i);
        for(i=1;i<=m;++i)
        {
            rg int l=read(),r=read();
            solve(l,r);
        }
        putout(root);
        puts("");
        return 0;
    }
  • 相关阅读:
    前端要懂的视频知识DASH协议(建议收藏)
    HTML5 video标签播放视频下载原理
    dash视频服务器本地搭建 (初探)
    纵论WebAssembly,JS在性能逆境下召唤强援
    详解volatile在C++中的作用
    C++ lambda表达式
    Java 从入门到进阶之路(十七)
    Java 从入门到进阶之路(十六)
    Java 从入门到进阶之路(十五)
    Java 从入门到进阶之路(十四)
  • 原文地址:https://www.cnblogs.com/c-wen/p/9163728.html
Copyright © 2011-2022 走看看