zoukankan      html  css  js  c++  java
  • luoguP3835 [模板]可持久化平衡树

    https://www.luogu.org/problemnew/show/P3835

    因为博主精力和实力有限,学不懂 fhq treap 了,因此只介绍 leafy tree 解法

    leafy tree 的本质是一颗平衡线段树,它的根节点保存整颗树的信息,是不会变的,因此可以高效的实现可持久化

    #include <bits/stdc++.h>
    #define update(u) if(u -> left -> size) u -> size = u -> left -> size + u -> right -> size, u -> value = u -> right -> value
    #define new_Node(a, b, c, d) (&(t[cnt++] = Node(a, b, c, d)))
    #define merge(a, b) new_Node(a -> size + b -> size, b -> value, a, b)
    #define ratio 4
    using namespace std;
    
    const int N = 500000 + 10;
    const int logN = 20;
    
    struct Node {
        int size, value;
        Node *left, *right;
        Node () {}
        Node (int a, int b, Node *c, Node *d) : size(a), value(b), left(c), right(d) {}
    }*root[N], *null, t[N * logN * 11 / 10];
    
    int n, cnt = 0;
    
    Node *maintain(Node *u) {
        Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
        if(cur -> left -> size > cur -> right -> size * ratio) cur -> left = maintain(cur -> left), cur -> right = maintain(cur -> right), cur -> right = merge(cur -> left -> right, cur -> right), cur -> left = cur -> left -> left; 
        if(cur -> right -> size > cur -> left -> size * ratio) cur -> left = maintain(cur -> left), cur -> right = maintain(cur -> right), cur -> left = merge(cur -> left, cur -> right -> left), cur -> right = cur -> right -> right; 
        return cur;
    }
    
    Node *ins(Node *u, int x) {
        Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
        if(cur -> size == 1) cur -> left = new_Node(1, min(cur -> value, x), null, null), cur -> right = new_Node(1, max(cur -> value, x), null, null);
        else if(x > cur -> left -> value) cur -> right = ins(cur -> right, x); else cur -> left = ins(cur -> left, x);
        update(cur); return cur;
    }
    
    Node *earse(Node *u, int x) {
        Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
        if(u -> size == 1 && u -> value != x) return cur;
        if(cur -> left -> size == 1 && x == cur -> left -> value) *cur = *cur -> right;
        else if(cur -> right -> size == 1 && x == cur -> right -> value) *cur = *cur -> left;
        else if(x > cur -> left -> value) cur -> right = earse(cur -> right, x); else cur -> left = earse(cur -> left, x);
        update(cur); return cur; 
    }
    
    int find(Node *u, int x) {
        if(u -> size == 1) return u -> value;
        return x > u -> left -> size ? find(u -> right, x - u -> left -> size) : find(u -> left, x);
    }
    
    int Rank(Node *u, int x) {
    //	printf("u -> value = %d, x = %d
    ", u -> value, x);
        if(u -> size == 1) return 1;
        return x > u -> left -> value ? Rank(u -> right, x) + u -> left -> size : Rank(u -> left, x); 
    }
    
    int main() {
        scanf("%d", &n);
        null = new Node(0, 0, 0, 0);
        root[0] = new Node(1, INT_MAX, null, null);
        for(int i = 1; i <= n; i++) {
            int a, t, pre;
            scanf("%d %d %d", &pre, &t, &a);
            if(t == 1) root[i] = maintain(ins(root[pre], a));
            if(t == 2) root[i] = maintain(earse(root[pre], a));
            if(t == 3) printf("%d
    ", Rank(root[pre], a)), root[i] = root[pre];
            if(t == 4) printf("%d
    ", find(root[pre], a)), root[i] = root[pre];
            if(t == 5) {
                int k = Rank(root[pre], a) - 1;
                if(k == 0) puts("-2147483647");
                else printf("%d
    ", find(root[pre], k));
                root[i] = root[pre];
            }
            if(t == 6) {
                int k = Rank(root[pre], a + 1);
                if(k == root[pre] -> size) puts("2147483647");
                else printf("%d
    ", find(root[pre], k));
                root[i] = root[pre];
            }
        }
        return 0;
    }
    

    关于新建节点时写

    #define new_Node(a, b, c, d) (&(*st[cnt++] = Node(a, b, c, d)))
    

    #define new_Node(a, b, c, d) (&(t[cnt++] = Node(a, b, c, d)))
    

    的区别

    leafy tree 实现可持久化平衡树的时候不能高效的垃圾回收,第一种就变成废物了,第二种在可持久化时更加高效

    关于旋转的时候写

    Node *maintain(Node *u) {
        Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
        if(cur -> left -> size > cur -> right -> size * ratio) cur -> left = maintain(cur -> left), cur -> right = maintain(cur -> right), cur -> right = merge(cur -> left -> right, cur -> right), st[--cnt] = cur -> left, cur -> left = cur -> left -> left;
        else if(cur -> right -> size > cur -> left -> size * ratio) cur -> left = maintain(cur -> left), cur -> right = maintain(cur -> right), cur -> left = merge(cur -> left, cur -> right -> left), st[--cnt] = cur -> right, cur -> right = cur -> right -> right;
        return cur;
    }
    
    

    Node *maintain(Node *u) {
        Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
        if(cur -> left -> size > cur -> right -> size * ratio) cur -> right = merge(cur -> left -> right, cur -> right), cur -> left = cur -> left -> left; 
        if(cur -> right -> size > cur -> left -> size * ratio) cur -> left = merge(cur -> left, cur -> right -> left), cur -> right = cur -> right -> right; 
        return cur;
    }
    

    的区别

    第一种情况需要在插入和删除的时候调用 maintain,是整棵树平衡,比较正常

    第二种情况在每次 update 之后 maintain,在可持久化时不能保证全局平衡,可能不太优秀?(这玩意是个玄学

    关于 merge 的高效实现(因为博主太菜了就咕咕咕了

  • 相关阅读:
    ListView
    ScrollView-电影列表
    ScrollView
    Image组件
    TextInput
    Touchable类组件
    Text
    View
    FlexBox
    StyleSheet
  • 原文地址:https://www.cnblogs.com/LJC00118/p/9555014.html
Copyright © 2011-2022 走看看