zoukankan      html  css  js  c++  java
  • Splay 区间反转

    同样的,我们以一道题来引入。

    传送门

    这次的任务比较少,只要求进行区间反转。区间反转?

    这个好像用啥都是O(n)的吧……(这次vector,set也救不了你了)

    我们来使用splay解决这个问题。我们既然要反转一段区间,那我们肯定要把这个区间弄到一个地方。我们想一下上次所讲的删除操作,我们把要删除的数的前驱后继都找了出来并且一个旋转到根,一个到根的右儿子。我们思考一下发现,如果把这个区间第一个数的前一个数(l-1)旋转到根,把区间最后一个数的后一个数(r+1)旋转到根的右儿子,那么现在根的右儿子的左子树就是这个区间了!

    然后我们就可以大力(划死)操作这棵子树,比如进行区间加减,区间翻转。翻转其实很简单,我们只要打上一个标记,在下放标记的时候,我们把当前节点的左右子树交换,把左右子树的标记全部异或1,把这个点的标记清零即可。(和线段树下放lazy标记非常像)

    然后实际操作的时候,比如我们要翻转区间2~4,我们不是真的去找这俩数在哪,因为我们要反转的话其实和数的大小是无关的,和下标的大小是有关的。取而代之的,我们找到在这棵平衡树中相对应的排名为2和排名为4的两个数的编号是多少,之后我们对它们进行操作即可。

    然后最后我们在输出整棵树的时候只要输出其中序遍历即可。

    我们来看一下代码吧!

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int N = 10000005;
    const int INF = 1000000009;
     
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct node
    {
        int fa,ch[2],son,cnt,tag,val;
    }t[M<<2];
    
    int n,m,data[M<<1],root,x,y,idx;
    
    bool get(int x)
    {
        return t[t[x].fa].ch[1] == x;
    }
    
    void pushup(int x)
    {
        t[x].son = t[t[x].ch[0]].son + t[t[x].ch[1]].son + 1;//题中无重复的数
    }
    
    void pushdown(int x)
    {
        if(x && t[x].tag)
        {
        t[t[x].ch[0]].tag ^= 1,t[t[x].ch[1]].tag ^= 1;
        swap(t[x].ch[0],t[x].ch[1]);
        t[x].tag = 0;
        }
    }
    
    void rotate(int x)
    {
        int y = t[x].fa,z = t[y].fa,k = get(x);
        t[z].ch[t[z].ch[1] == y] = x,t[x].fa = z;
        t[y].ch[k] = t[x].ch[k^1],t[t[y].ch[k]].fa = y;
        t[x].ch[k^1] = y,t[y].fa = x;
        pushup(x),pushup(y);
    }
    
    void splay(int x,int goal)
    {
        while(t[x].fa != goal)
        {
        int y = t[x].fa,z = t[y].fa;
        if(z != goal) (t[y].ch[0] == x) ^ (t[z].ch[0] == y) ? rotate(x) : rotate(y);
        rotate(x);
        }
        if(goal == 0) root = x;
    }
    
    int rk(int x)//找排名
    {
        int u = root;
        while(1)
        {
        pushdown(u);
        if(t[t[u].ch[0]].son >= x) u = t[u].ch[0];
        else
        {
            x -= (t[t[u].ch[0]].son + 1);
            if(!x) return u;
            u = t[u].ch[1];
        }
        }
    }
    
    int build(int f,int l,int r)//直接构造一棵完美的splay
    {
        if(l > r) return 0;
        int mid = (l+r) >> 1,u = ++idx;
        t[u].val = data[mid],t[u].fa = f;//注意一定是mid的值!
        t[u].ch[0] = build(u,l,mid-1);
        t[u].ch[1] = build(u,mid+1,r);
        pushup(u);
        return u;
    }
    
    void turn(int x,int y)
    {
        int a = rk(x), b = rk(y+2);//因为插入了正负INF,所以相对应都向后移了一位
        splay(a,0),splay(b,a);//以下操作上面都说过
        pushdown(root);
        int g = t[t[root].ch[1]].ch[0];
        t[g].tag ^= 1;
    }
    
    void write(int x)//输出中序遍历
    {
        pushdown(x);
        if(t[x].ch[0]) write(t[x].ch[0]);
        if(t[x].val != INF && t[x].val != -INF) printf("%d ",t[x].val);
        if(t[t[x].ch[1]].val) write(t[x].ch[1]);
    }
    
    int main()
    {
        n = read(),m = read();
        rep(i,1,n) data[i+1] = i;
        data[1] = -INF,data[n+2] = INF;//防止出错
        root = build(0,1,n+2);
        rep(i,1,m) x = read(),y = read(),turn(x,y);
        write(root);
        return 0;
    }
  • 相关阅读:
    编译Filebeat源码
    一些常用的shell写法
    设置tomcat默认访问的项目
    修改Linux软件源
    k8s创建使用nfs的StorageClass
    使用NFS服务实现文件共享
    idea配置代码注释模板
    redis cluster(集群)模式的创建方式
    etcd简单测试类java版
    Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
  • 原文地址:https://www.cnblogs.com/captain1/p/9734410.html
Copyright © 2011-2022 走看看