zoukankan      html  css  js  c++  java
  • 权值线段树

    权值线段树的功能有

    • 查询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;
    }
    
  • 相关阅读:
    es6新增特性,数组的操作方法
    导航钩子有哪几种,如何将数据传入下一个点击的路由页面
    父组件如何获取子组件数据,子组件如何获取父组件数据,父子组件如何传值
    watch和computed的区别
    vue页面中定时器的使用
    table表格,顶端对齐
    计算机组成原理8-FPGA、ASIC、TPU、虚拟机
    vue中使用socket连接后台
    计算机组成原理7-CISC和RISC、GPU
    计算机组成原理6-流水线、多发射和超标量、SIMD、异常
  • 原文地址:https://www.cnblogs.com/Emcikem/p/12175702.html
Copyright © 2011-2022 走看看