• 权值线段树


    权值线段树的功能有

    • 查询x在整个区间出现的次数
    • 查询[L,R]的数字出现的次数
    • 所有数中出现次数第k大的数字

    基于线段树和二分的思想

    定义(int tree[maxn];)
    tree[i]表示某段区间数字出现的次数

    一般需要离散化操作

    插入数据

    void update(int l,int r,int rt,int x,int op){//插入op个x
        if(l == r){
            tree[rt] += op;
            return;
        }
        int mid = (l + r) >> 1;
        if(x <= mid)update(lson,x,op);
        else update(rson,x,op);
        pushup(rt);
    }
    

    查询x在整个区间出现的次数

    int find(int l,int r,int rt,int x){//查询x在整个区间出现的次数
        if(l == r)return tree[rt];
        int mid = (l + r) >> 1;
        if(x <= mid)return find(lson,x);
        else return find(rson,x);
    }
    

    查询[L,R]的数字出现的次数

    int find2(int l,int r,int rt,int L,int R){//查询[L,R]的数字出现的次数
        if(L <= l && r <= R)return tree[rt];
        int mid = (l + r) >> 1;
        if(R <= mid)return find2(lson,L,R);
        if(L > mid)return find2(rson,L,R);
        return find2(lson,L,R) + find2(rson,L,R);
    }
    

    查询第k大数

    只需要知道右节点数字出现的次数即可
    权值线段树是查询整个区间的,主席树是对于区间查询第k值的

    int kth(int l,int r,int rt,int k){//所有数中出现次数第k大的数字
        if(l == r)return l;
        int mid = (l + r) >> 1;
        int rs = tree[rs(rt)];//只看右结点即可
        if(k <= rs)return kth(rson,k);//在右边
        else return kth(lson,k - rs);//在左边,变为第k - rs大的数字
    }
    

    模板

    #include <iostream>
    #include <cstdio>
    #define ls(rt) rt<<1
    #define rs(rt) rt<<1|1
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    using namespace std;
    const int maxn = 1e5 + 5;
    int tree[maxn >> 2];//下标是数字,tree[i]某段区间数字出现的次数
    void pushup(int rt){
        tree[rt] = tree[ls(rt)] + tree[rs(rt)];
    }
    void update(int l,int r,int rt,int x,int op){//插入op个x
        if(l == r){
            tree[rt] += op;
            return;
        }
        int mid = (l + r) >> 1;
        if(x <= mid)update(lson,x,op);
        else update(rson,x,op);
        pushup(rt);
    }
    int find(int l,int r,int rt,int x){//查询x在整个区间出现的次数
        if(l == r)return tree[rt];
        int mid = (l + r) >> 1;
        if(x <= mid)return find(lson,x);
        else return find(rson,x);
    }
    int find2(int l,int r,int rt,int L,int R){//查询[L,R]的数字出现的次数
        if(L <= l && r <= R)return tree[rt];
        int mid = (l + r) >> 1;
        if(R <= mid)return find2(lson,L,R);
        if(L > mid)return find2(rson,L,R);
        return find2(lson,L,R) + find2(rson,L,R);
    }
    int kth(int l,int r,int rt,int k){//所有数中出现次数第k大的数字
        if(l == r)return l;
        int mid = (l + r) >> 1;
        int rs = tree[rs(rt)];//只看右结点即可
        if(k <= rs)return kth(rson,k);//在右边
        else return kth(lson,k - rs);//在左边,变为第k - rs大的数字
    }
    // int rank(int l,int r,int rt,int x){//查询x在全局的排名
    
    // }
    // int pre(int l,int r,int rt,int x){//查询前驱,小于等于x的最大
    
    // }
    // int ore(int l,int r,int rt,int x){//查询后继,大于x的最大值
    
    // }
    int n;
    int main(){
        int m;
        cin >> n >> m;
        int x;
        for(int i = 0; i < n; i++){
            scanf("%d",&x);
            update(1,n,1,x,1);
        }
        
        return 0;
    }
    
  • 相关阅读:
    LeetCode--Array--Two sum (Easy)
    LeetCode--Unique Email Addresses & Hamming Distance (Easy)
    LeetCode--Squares of a Sorted Array && Robot Return to Origin (Easy)
    LeetCode--Sort Array By Parity && N-Repeated Element in Size 2N Array (Easy)
    LeetCode 11月第1周题目汇总
    LeetCode 十月份题目汇总
    【每天一题】LeetCode 172. 阶乘后的零
    【每天一题】LeetCode 121. 买卖股票的最佳时机
    【每天一题】LeetCode 0107. 自底向上层遍历二叉树
    【每天一题】LeetCode 0067. 二进制求和
  • 原文地址:https://www.cnblogs.com/Emcikem/p/12175702.html
Copyright © 2020-2023  润新知