zoukankan      html  css  js  c++  java
  • P3391 【模板】文艺平衡树 题解

    有关splay的初始了解

    题目描述

    您需要写一种数据结构(可参考题目标题),来维护一个有序数列。

    其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 15 4 3 2 15 4 3 2 1,翻转区间是 [2,4][2,4][2,4] 的话,结果是 5 2 3 4 15 2 3 4 15 2 3 4 1。

    输入格式

    第一行两个正整数 n,mn,mn,m,表示序列长度与操作个数。序列中第 iii 项初始为 iii。
    接下来 mmm 行,每行两个正整数 l,rl,rl,r,表示翻转的区间。

    输出格式

    输出一行 nnn 个正整数,表示原始序列经过 mmm 次变换后的结果。

    输入输出样例

    输入 #1
    5 3
    1 3
    1 3
    1 4
    输出 #1
    4 3 2 1 5

    说明/提示

    【数据范围】
    对于 100% 的数据,1≤n,m≤1000001≤l≤r≤n1这是什么bug。。。


    显然,这道题和数的值并没有什么关系。

    于是我们考虑根据数的编号建树。因为初始状态,位置为i的数值也为i,所以我们将他们从1——n编号,编号即为数的值,于是我们建树,最后一通胡乱搞后将树中序遍历输出,即为答案。

    大体思路形成,考虑如何胡乱搞这个交换。

    脑中模拟一遍,中序遍历先访问左子树,然后是根节点,再往后就是右子树。如果要满足题目中所说的区间交换的效果,也就是输出右子树的点,然后是根节点,再往后是左子树。这个效果等同于交换左右子树,然后输出方式不变(中序)。也就是说,递归交换左右子树即可。

    最后,根据交换两次相当于没有交换这一事实,我们可以注意到操作的可累加性,相当于线段树中为了降低时间复杂度,打上lazytag,加减操作摞在一起下传一样。我们也给这一道题加个lazytag,只不过里面记录的是交换信息罢了。这样我们也降低了时间复杂度。

    至于交换的方法与splay的关系:对于我们要交换的区间[l,r],我们只需要取l-1和r+1所代表的节点(Kth操作)然后将这两个节点一个旋转到根节点,另一个旋转到根节点的右儿子上,则要修改的区间就是根的右儿子的左子树(右儿子的左子树所有节点值小于右儿子大于根节点,正好代表l到r的区间),直接给右儿子左子树打上lazytag即可即可

    对于1-n整体旋转的特殊操作,我们只需定义序号为0和INF的虚拟节点作为l-1和r+1即可。

    code:

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iomanip>
    #include<algorithm>
    #include<ctime>
    #include<queue>
    #include<stack>
    #define rg register
    #define lst long long
    #define N 1000050
    using namespace std;
    
    int n,m,tot,root;
    struct Node{
        int ch[2];
        int v,fa;
        int size;
        int lazy;
    }ljl[N];
    
    inline int read()
    {
        rg int s=0,m=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')m=0,ch=getchar();
        while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
        return m?s:-s;
    }
    
    inline void Pushup(rg int now)
    {
        ljl[now].size=ljl[ljl[now].ch[0]].size+ljl[ljl[now].ch[1]].size+1;
    }
    
    inline void Pushdown(rg int now)
    {
        if(ljl[now].lazy)
        {
            ljl[ljl[now].ch[0]].lazy^=1;
            ljl[ljl[now].ch[1]].lazy^=1;
            swap(ljl[now].ch[0],ljl[now].ch[1]);
            ljl[now].lazy=0;
        }
    }
    
    inline void rotate(rg int x)
    {
        rg int y=ljl[x].fa,z=ljl[y].fa;
        rg int k=ljl[y].ch[1]==x;
        ljl[z].ch[ljl[z].ch[1]==y]=x;
        ljl[x].fa=z;
        ljl[y].ch[k]=ljl[x].ch[k^1];
        ljl[ljl[x].ch[k^1]].fa=y;
        ljl[x].ch[k^1]=y;
        ljl[y].fa=x;
        Pushup(x),Pushup(y);
    }
    
    inline void splay(rg int x,rg int goal)
    {
        while(ljl[x].fa!=goal)
        {
            rg int y=ljl[x].fa,z=ljl[y].fa;
            if(z!=goal)(x==ljl[y].ch[0])^(y==ljl[z].ch[0])?rotate(x):rotate(y);
            rotate(x);
        }
        if(goal==0)root=x;
    }
    
    inline void Insert(rg int x)
    {
        int now=root,fa=0;
        while(now)fa=now,now=ljl[now].ch[x>ljl[now].v];
        now=++tot;
        if(fa)ljl[fa].ch[x>ljl[now].v]=now;
        ljl[now].ch[0]=ljl[now].ch[1]=0;
        ljl[now].v=x;ljl[now].fa=fa;
        ljl[now].size=1;
        splay(now,0);
    }
    
    inline int Kth(rg int x)
    {
        rg int now=root;
        while(233)
        {
            Pushdown(now);
            if(x>ljl[ljl[now].ch[0]].size+1)
                x-=ljl[ljl[now].ch[0]].size+1,now=ljl[now].ch[1];
            else if(ljl[ljl[now].ch[0]].size>=x)now=ljl[now].ch[0];
            else return now;
        }
    }
    
    inline void Work(rg int le,rg int ri)
    {
        rg int qq=Kth(le);
        rg int hj=Kth(ri+2);
        splay(qq,0),splay(hj,qq);
        ljl[ljl[ljl[root].ch[1]].ch[0]].lazy^=1;
    }
    
    void Write(rg int now)
    {
        Pushdown(now);
        if(ljl[now].ch[0])Write(ljl[now].ch[0]);
        if(ljl[now].v>1&&ljl[now].v<n+2)printf("%d ",ljl[now].v-1);
        if(ljl[now].ch[1])Write(ljl[now].ch[1]);
    }
    
    int main()
    {
        n=read(),m=read();
        for(rg int i=1;i<=n+2;++i)Insert(i);
        for(rg int i=1;i<=m;++i)
        {
            rg int le=read(),ri=read();
            Work(le,ri);
        }
        Write(root);
        return 0;
    }

    代码转自这位巨佬

    撒花。

  • 相关阅读:
    easyExcel入门
    UML-从需求到设计--迭代进化
    UML-操作契约总结
    102. Binary Tree Level Order Traversal
    98. Validate Binary Search Tree
    95. Unique Binary Search Trees II
    96. Unique Binary Search Trees
    94. Binary Tree Inorder Traversal
    84. Largest Rectangle in Histogram
    92. Reverse Linked List II
  • 原文地址:https://www.cnblogs.com/lbssxz/p/12819928.html
Copyright © 2011-2022 走看看