zoukankan      html  css  js  c++  java
  • BZOJ 3223 文艺平衡树

    BZOJ 3223 文艺平衡树

    题意

    一个 1~n 的序列,有m次询问,每次询问翻转其中的一个区间。输出最后的区间。

    题解

    这是一棵加lazy的平衡树……

    首先,翻转区间可以通过区间内所有节点的左右儿子实现。显然我们不能暴力处理所有的点,所以我们要打lazy标记。

    既然要打lazy,首先要区间内所有节点都在一棵子树里面:设区间为 [l, r],把序列中第 l - 1 个节点旋转到根节点,然后把第 r + 1 个节点旋转到根节点下面(显然这个节点会是根节点的右儿子),此时整个 [l, r] 区间中的节点都在第 r + 1 个节点的左子树中了。然后把这个子树的根节点打上lazy标记即可。

    什么时候下放呢?Find的时候,每访问到一个节点都要下放;而旋转的时候,涉及到的节点在find时都已经下放完毕了,所以不用考虑下放的事情。还有就是最后输出的时候别忘了下放。

    自己犯过的错误:

    1. which(u) ? xxx, xxx : xxx, xxx; 冒号左右的式子都要打括号;
    2. 这里的 Find 函数找的是“序列中的第x个点”,不是值第x大的点。
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #define space putchar(' ')
    #define enter putchar('
    ')
    using namespace std;
    typedef long long ll;
    template <class T>
    void read(T &x){
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
    	if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
    	x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    const int N = 100005;
    int n, m;
    int root = 1, idx, id[N] = {-1}, sze[N], ls[N], rs[N], fa[N], lazy[N];
    #define which(x) (ls[fa[(x)]] == (x))
    
    void upt(int u){
        sze[u] = sze[ls[u]] + sze[rs[u]] + 1;
    }
    void rotate(int u){
        int v = fa[u], w = fa[v], b = which(u) ? rs[u] : ls[u];
        if(w) which(v) ? ls[w] = u : rs[w] = u;
        which(u) ? (ls[v] = b, rs[u] = v) : (rs[v] = b, ls[u] = v);
        if(b) fa[b] = v;
        fa[v] = u, fa[u] = w;
        upt(v), upt(u);
    }
    void splay(int u, int tar){
        while(fa[u] != tar){
    	if(fa[fa[u]] != tar){
    	    if(which(u) == which(fa[u])) rotate(fa[u]);
    	    else rotate(u);
    	}
    	rotate(u);
        }
        if(!tar) root = u;
    }
    void swap_son(int u){
        if(!u) return;
        lazy[u] ^= 1;
        swap(ls[u], rs[u]);
        upt(u);
    }
    void pushdown(int u){
        if(!lazy[u]) return;
        swap_son(ls[u]), swap_son(rs[u]);
        lazy[u] = 0;
    }
    int find(int x){
        int u = root;
        pushdown(u);
        while(sze[ls[u]] != x && u){
    	if(sze[ls[u]] >= x + 1) u = ls[u];
    	else x -= sze[ls[u]] + 1, u = rs[u];
    	pushdown(u);
        }
        return u;
    }
    void reverse(int l, int r){
        splay(find(l - 1), 0);
        splay(find(r + 1), root);
        swap_son(ls[rs[root]]);
    }
    int build(int l, int r){
        int mid = (l + r) >> 1, u = ++idx;
        id[u] = mid;
        if(mid > l) ls[u] = build(l, mid - 1), fa[ls[u]] = u;
        if(mid < r) rs[u] = build(mid + 1, r), fa[rs[u]] = u;
        upt(u);
        return u;
    }
    void out(int u){
        pushdown(u);
        if(ls[u]) out(ls[u]);
        if(id[u] && id[u] <= n) write(id[u]), space;
        if(rs[u]) out(rs[u]);
    }
    
    int main(){
        read(n), read(m);
        build(0, n + 1);
        while(m--){
    	int l, r;
    	read(l), read(r);
    	reverse(l, r);
        }
        out(root), enter;
        return 0;
    }
    
  • 相关阅读:
    js图片轮换
    PHP如何打造一个高可用高性能的网站呢?
    php中浮点数计算问题
    jQuery ajax()使用serialize()提交form数据
    js最新手机号码、电话号码正则表达式
    swoole是如何实现任务定时自动化调度的?
    Facebook的“零售吸引力”,互联网营销 狼人:
    Google勇敢新世界,互联网营销 狼人:
    Facebook的成功之道,互联网营销 狼人:
    李彦宏分享百度危机中如何“弯道超车”,互联网营销 狼人:
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/BZOJ3223.html
Copyright © 2011-2022 走看看