权值线段树
权值线段树的功能有
- 查询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;
}
I‘m Stein, welcome to my blog
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· .NET Core GC压缩(compact_phase)底层原理浅谈
· Winform-耗时操作导致界面渲染滞后
· Phi小模型开发教程:C#使用本地模型Phi视觉模型分析图像,实现图片分类、搜索等功能
· 语音处理 开源项目 EchoSharp