zoukankan      html  css  js  c++  java
  • AcWing 2437. Splay

    题目链接

    解题思路

      splay的模版题,首先先把l-1这个位置的结点splay到根,然后再把r+1这个位置的结点splay到l-1的下面,那么r+1的左子树就是区间l到r,然后用懒标记来交换子树中每个节点的左右儿子即可

    const int maxn = 1e5+10;
    int n, m;
    struct Node {
        int s[2], p, v; //s0:左儿子 s1:右儿子
        int sz, f;
        void init(int _v, int _p) {
            v = _v, p = _p;
            sz = 1;
        }
    } tr[maxn];
    int rt, idx;
    void push_up(int x) {
        tr[x].sz = tr[tr[x].s[0]].sz+tr[tr[x].s[1]].sz+1;
    }
    void push_down(int x) {
        if (tr[x].f) {
            swap(tr[x].s[0], tr[x].s[1]);
            tr[tr[x].s[0]].f ^= 1;
            tr[tr[x].s[1]].f ^= 1;
            tr[x].f = 0;
        }
    }
    void rotate(int x) {
        int y = tr[x].p, z = tr[y].p;
        int k = tr[y].s[1] == x; //0: x是y的左儿子  1:x是y的右儿子
        tr[z].s[tr[z].s[1]==y] = x, tr[x].p = z;
        tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y;
        tr[x].s[k^1] = y, tr[y].p = x;
        push_up(y), push_up(x);
        /*
            x是y的左儿子:
                y右旋
                y是z的左儿子:
                    x设成z的左儿子
                y是z的右儿子:
                    x设成z的右儿子
                x的右儿子挂到y的左边
                y设成x的右儿子
            x是y的右儿子:
                y左旋
                y是z的左儿子:
                    x设成z的左儿子
                y是z的右儿子
                    x设成z的右儿子
                x的左儿子挂到y的右边
                y设成x的左儿子
        */
    }
    void splay(int x, int k) {
        while(tr[x].p!=k) {
            int y = tr[x].p, z = tr[y].p;
            if (z!=k) 
                if ((tr[y].s[1]==x)^(tr[z].s[1]==y)) rotate(x); //相同先旋ff,不同旋f
                else rotate(y);
            rotate(x);
        }
        if (!k) rt = x;
    }
    void insert(int v) {
        int u = rt, p = 0;
        while(u) p = u, u = tr[u].s[v>tr[u].v];
        u = ++idx;
        if (p) tr[p].s[v>tr[p].v] = u;
        tr[u].init(v, p);
        splay(u, 0);
    }
    int get_k(int k) {
        int u = rt;
        while(1) {
            push_down(u);
            if (tr[tr[u].s[0]].sz >= k) u = tr[u].s[0];
            else if (tr[tr[u].s[0]].sz+1 == k) return u;
            else k -= tr[tr[u].s[0]].sz + 1, u = tr[u].s[1];
        }
        return -1;
    }
    void output(int u) {
        push_down(u);
        if (tr[u].s[0]) output(tr[u].s[0]);
        if (tr[u].v >= 1 && tr[u].v <= n) cout << tr[u].v << ' ';
        if (tr[u].s[1]) output(tr[u].s[1]);
    }
    int main() {
        IOS;
        cin >> n >> m;
        for (int i = 0; i<=n+1; ++i) insert(i);
        while(m--) {
            int l, r; cin >> l >> r;
            l = get_k(l), r = get_k(r+2);
            //先把l-1 splay到根节点,再把r+1 splay到l-1 的下面,r+1的左子树就是区间l到r
            splay(l, 0), splay(r, l);
            //因为前面多插入了一个0,所以左右区间都+1
            tr[tr[r].s[0]].f ^= 1;
        }
        output(rt);
        return 0;
    }
    
  • 相关阅读:
    容器级虚拟化如何进行资源分配
    容器虚拟化实现的原理
    tensorflow报cudnn错误
    nginx调优
    mysql主从原理及配置
    新安装mysql,如何提升mysql安全性
    LINUX系统软件安装和卸载的常见方法
    如何增加黑客通过ssh入侵的难度--保护ssh的三把锁
    ubuntu-docker入门到放弃(八)创建支持SSH服务的镜像
    ubuntu-docker入门到放弃(七)操作系统
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/15085178.html
Copyright © 2011-2022 走看看