权值线段树的功能有
- 查询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; }
来源:https://www.cnblogs.com/Emcikem/p/12175702.html