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

    【题目链接】

              点击打开链接

    【算法】

             本题是splay区间操作的模板题

             我们每个点的权值设为”当前在序列中的排名“,根据二叉排序树的性质,这棵树的中序遍历就是当前序列

             如果我们要获得一段区间[l,r],那么我们将l-1splay到根节点,将r+1splay到根节点的右子树的根,我们发现,根节点

             的右节点的左子树就是区间[l,r]

             对于翻转操作,我们其实只需将“根节点的右节点的左子树”这棵树不断地进行左右子树交换就可以了,但是,为了避免

             交换次数太多,我们可以像线段树那样,每个点都存一个懒惰标记

    【代码】

             

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 100000
    
    int i,N,M,l,r;
    
    template <typename T> inline void read(T &x) {
            int f = 1; x = 0;
            char c = getchar();
            for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
            for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
            x *= f;
    }
    
    template <typename T> inline void write(T x) {
        if (x < 0) { putchar('-'); x = -x; }
        if (x > 9) write(x/10);
        putchar(x%10+'0');
    }
    
    template <typename T> inline void writeln(T x) {
        write(x);
        puts("");
    }
    
    struct Splay {
            int root,total;
            struct Node {
                    int size,val,son[2],fa;
                    bool rev;
            } Tree[MAXN+10];
            inline bool get(int x) {
                    return Tree[Tree[x].fa].son[1] == x;
            }
            inline void update(int index) {
                    Tree[index].size = Tree[Tree[index].son[0]].size + Tree[Tree[index].son[1]].size + 1;
            }
            inline void build(int index,int l,int r) {
                    int mid = (l + r) >> 1;
                    Tree[index].rev = false;
                    Tree[index].val = mid;
                    Tree[index].size = 1;
                    if (l == r) return;
                    if (l <= mid - 1) {
                            ++total;
                            Tree[index].son[0] = total;
                            Tree[total].fa = index;
                            build(total,l,mid-1);
                            Tree[index].size += Tree[Tree[index].son[0]].size;
                    }
                    if (mid + 1 <= r) {
                            ++total;
                            Tree[index].son[1] = total;
                            Tree[total].fa = index;
                            build(total,mid+1,r);
                            Tree[index].size += Tree[Tree[index].son[1]].size;
                    }
            }
            inline void rotate(int x) {
                    int f = Tree[x].fa,g = Tree[f].fa,
                    tmpx = get(x),tmpf = get(f);
                    if (Tree[f].rev) pushdown(f);
                    if (Tree[x].rev) pushdown(x);
                    if (!f) return;
                    Tree[f].son[tmpx] = Tree[x].son[tmpx^1];
                    if (Tree[x].son[tmpx^1]) Tree[Tree[x].son[tmpx^1]].fa = f;
                    Tree[x].son[tmpx^1] = f;
                    Tree[f].fa = x;
                    Tree[x].fa = g;
                    if (g) Tree[g].son[tmpf] = x;
                    update(f);
                    update(x);
            }
            inline void splay(int x) {
                    int f;
                    for (f = Tree[x].fa; (f = Tree[x].fa); rotate(x)) 
                            if (Tree[f].fa) rotate(get(x) == get(f) ? f : x);  
                    root = x;
            }
            inline void splayII(int x) {
                    int f;
                    for (f = Tree[x].fa; (f = Tree[x].fa) != root; rotate(x)) {
                            if (Tree[f].fa != root) rotate(get(x) == get(f) ? f : x);  
                    }
            }
            inline void pushdown(int index) {
                    swap(Tree[index].son[0],Tree[index].son[1]);
                    Tree[Tree[index].son[0]].rev ^= 1;
                    Tree[Tree[index].son[1]].rev ^= 1;
                    Tree[index].rev = 0;
            }
            inline int query_pos(int x) {
                    int index = root;
                    while (true) {
                            if (Tree[index].rev) pushdown(index);
                            if (x <= Tree[Tree[index].son[0]].size) index = Tree[index].son[0];
                            else {
                                    x -= Tree[Tree[index].son[0]].size;
                                    if (x == 1) return index;
                                    --x;
                                    index = Tree[index].son[1];
                            }
                    }
            }
            inline int query_val(int x) {
                    int pos = query_pos(x);
                    return Tree[pos].val;
            }
            inline void reverse(int l,int r) {
                    int x = query_pos(l-1),
                            y = query_pos(r+1);
                    splay(x); splayII(y);
                    Tree[Tree[Tree[root].son[1]].son[0]].rev ^= 1;
            }
    } T;
    
    int main() {
            
            read(N); read(M);
            
            T.total = 1;
            T.root = 1;
            T.build(1,1,N+2);
            
            while (M--) {
                    read(l); read(r);
                    T.reverse(l+1,r+1);            
            }
            
            for (i = 2; i <= N + 1; i++) {
                    if (i == 2) write(T.query_val(i)-1);
                    else { putchar(' '); write(T.query_val(i)-1); }
            }
            putchar(' ');
            
            puts("");
            
            return 0;
        
    }
  • 相关阅读:
    设计模式笔记(22)状态模式(行为型)
    设计模式笔记(16)解释器模式(行为型)
    Lable和Literal控件的使用和区别
    设计模式笔记(15)命令模式(行为型)
    设计模式笔记(25)总结
    在JS方法中返回多个值的三种方法
    SQL 左外连接,右外连接,全连接,内连接
    面试集萃
    ASP.NET MVC如何使用Ajax的辅助方法
    ASP.NET MVC+EF框架+EasyUI实现权限管理(附源码)
  • 原文地址:https://www.cnblogs.com/evenbao/p/9196414.html
Copyright © 2011-2022 走看看