• 文艺平衡树(Splay)


    题意

    给出一个序列,m次操作翻转区间[l,r],如1,5,4,2变成2,4,5,1

    求最后的序列

    n,m100000

    题解

    普通的splay维护的权值,如果维护序列的话就维护序列下标即可,即splay的中序遍历就是原序列。

    提取一段区间[l,r]就把l-1旋到根,r+1旋到根的右儿子,那么这段区间就在r+1的左二子那部分。

    提取出来后一段区间的结构都是一颗树,那么翻转区间就在树的根打上标记代表他的左右儿子需要交换。

    标记下传在find中即可,因为所有操作都要经过这一步。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100005;
    const int oo=100000000;
    int n,m,root,num,a[maxn];
    struct point{
        int size,fa,v,tag,s[2];
    }tr[maxn];
    
    template<class T>inline void read(T &x){
        x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    }
    
    int build(int l,int r,int f){
        if(l>r) return 0;
        int now=++num,mid=(l+r)>>1;
        tr[now].fa=f;
        tr[now].v=a[mid];
        tr[now].size++;
        tr[now].s[0]=build(l,mid-1,now);
        tr[now].s[1]=build(mid+1,r,now);
        tr[now].size+=tr[tr[now].s[1]].size+tr[tr[now].s[0]].size;
        return now;
    }
    
    
    void pushdown(int x){
        if(!tr[x].tag) return ;
        tr[tr[x].s[0]].tag^=1;
        tr[tr[x].s[1]].tag^=1;
        swap(tr[x].s[0],tr[x].s[1]);
        tr[x].tag=0;
    }
    
    int find(int x){
        int now=root;
        while(1){
            pushdown(now);
            if(x<=tr[tr[now].s[0]].size) {now=tr[now].s[0]; continue;}
            x=x-(tr[tr[now].s[0]].size+1);
            if(!x) return now;
            now=tr[now].s[1];
        }
    }
    
    int indenti(int x){ return tr[tr[x].fa].s[1]==x;}
    
    void connect(int x,int y,int d){
        tr[x].fa=y;
        tr[y].s[d]=x;
    }
    
    void update(int x){
        int ls=tr[x].s[0],rs=tr[x].s[1];
        tr[x].size=tr[ls].size+tr[rs].size+1;
    }
    
    void rotate(int x){
        int f=tr[x].fa,ff=tr[f].fa;
        int d1=indenti(x);
        int d2=indenti(f);
        int cs=tr[x].s[d1^1];
        connect(x,ff,d2);
        connect(f,x,d1^1);
        connect(cs,f,d1);
        update(f);
        update(x);
    }
    
    void splay(int x,int go){
        if(go==root) root=x;
        go=tr[go].fa;
        while(tr[x].fa!=go){
            int f=tr[x].fa;
            if(tr[f].fa==go) rotate(x);
            else if(indenti(x)==indenti(f)) {rotate(f);rotate(x);}
            else {rotate(x);rotate(x);}
        }
    }
    
    void cx(int x,int y){
        int l=find(x-1),r=find(y+1);//找区间[x,y]的前驱和后继
        splay(l,root);
        splay(r,tr[l].s[1]);
        int pos=tr[root].s[1];
        pos=tr[pos].s[0];//找到[x,y]整颗子树的根
        tr[pos].tag^=1; 
    }
    
    void nice(int x){
        pushdown(x);
        if(tr[x].s[0]) nice(tr[x].s[0]);
        if(tr[x].v!=oo&&tr[x].v!=-oo) printf("%d ",tr[x].v);
        if(tr[x].s[1]) nice(tr[x].s[1]);
    }
    
    int main(){
        read(n);read(m);
        a[1]=-oo;a[n+2]=oo;
        for(int i=1;i<=n;i++) a[i+1]=i;
        root=build(1,n+2,0);
        for(int i=1;i<=m;i++){
            int x,y;read(x);read(y);
            cx(x+1,y+1);//加入了-oo 
        }
        nice(root);
    }
    View Code
  • 相关阅读:
    字符串和编码
    Python基础
    输入和输出
    Python代码运行助手
    使用文本编辑器
    第一个Python程序
    pycharm中创建并设置docker解释器
    docker 在windows上的使用
    Python time datetime模块
    Linux安装字体文件
  • 原文地址:https://www.cnblogs.com/sto324/p/11297573.html
Copyright © 2020-2023  润新知