zoukankan      html  css  js  c++  java
  • 主席树

    省赛主席树模板题和zyn大佬想了两个小时没想出来 太菜了太菜了

    要是我能强到和HJT大神一样能在考场上想出一个主席树一样的东西就好了哈哈哈

    感觉主席树就是一个线段树加前缀和加一个优化

    主要用于求区间第k小的问题

    如果区间是固定的 用线段树或者是归并都好求

    用线段树的话 每个节点就存这个区间有的数的个数 如果要查询的k比节点左子树的权值要小于等于的话

    说明这个区间的左孩子里至少有k个数 那第k小肯定就在左孩子区间里了

    如果要求一个动态的区间【L,R】中的第k小

    我们可以对区间【1,L】和【1,R】建线段树

    因为线段树的节点可以相加减

    所以结果就类似于前缀和 减一下 就可以了

    但是这样的话时间和空间都会爆

    主席树就是发现 每次更改一个节点的值的时候 一棵树上只有一条路径会被更改 也就是logn个节点

    第i棵线段树和第i+1棵 只需要修改logn个节点

    所以每次只创建和上次不同的节点 相同的就用之前的就可以了

    为了节省空间,可以将第 00 棵线段树置为空,每次插入一个新叶子节点时接入一条长度为 O(log n)O(logn)的链。总空间、时间复杂度仍为 O(n log n)O(nlogn)

    查询时构造整棵线段树,需要构造 O(n log n)O(nlogn) 个节点,但每次查询只会用到 O(log n)O(logn) 个节点,直接动态构造这些节点即可。为了方便,可以不显式构造这些节点,而是直接用两棵线段树上的值相减。

    需要注意的是

    主席树需要动态开点

    因为普通的线段树 我们可以算出左右孩子的下标

    但是主席树是变化的 就需要动态开点 每个节点要多存一下左右孩子的下标

    来!上模板!

    struct node{
        int sum, l, r;//l到r之间数的个数 左儿子右儿子编号
    }T[maxn * 40];
    int x, y, k;
    int root[maxn], cnt, a[maxn], n, m;
    
    void update(int l, int r, int &x, int y, int pos)
    {
        T[++cnt] = T[y];
        T[cnt].sum++;
        x = cnt;
        if(l == r) return;
        int mid = (l + r) / 2;
        if(mid >= pos)
            update(l, mid, T[x].l, T[y].l, pos);
        else
            update(mid + 1, r, T[x].r, T[y].r, pos);
    }
    
    int query(int l, int r, int x, int y, int k)
    {
        if(l == r) return l;
        int mid = (l + r) / 2;
        int sum = T[T[y].l].sum - T[T[x].l].sum;
        if(sum >= k) return query(l, mid, T[x].l, T[y].l, k);
        return query(mid +1, r, T[x].r, T[y].r, k - sum);
    }
    
    vector<int>v;
    int getid(int x)
    {
        return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
    }//离散化


  • 相关阅读:
    tushare包使用案例
    Matplotlib模块:绘图和可视化
    pandas使用
    django 表操作
    元数据Meta
    django关系类型字段
    django项目模型字段
    django项目mysite 2
    django安装使用xadmin
    GCC版本中没有GLIBCXX_3.4.15错误
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9643405.html
Copyright © 2011-2022 走看看