【学习笔记】权值线段树
原文链接
挖坑待填
一. 权值线段树
权值线段树即一种线段树,以序列的数值为下标。节点里所统计的值为节点所对应的区间 中, 这个值域中所有数的出现次数。
举个例子,有一个长度为 的序列 {}。
那么统计每个数出现的次数。易知 出现了 次, 出现了 次, 出现了 次,出现了 次, 出现了 次。
那么我们可以建出一棵这样的权值线段树:

从网上搬的。节点中的数字代表节点对应区间中所有数的出现次数。
-
每个叶子节点的值: 代表 这个值的出现次数。
-
非叶子节点的值:代表了某一个值域内,所有值出现次数的和。
上面的权值线段树中, 并没有出现,然而却被建出。如果序列的数 的取值范围是 ,那么我们的树就需要 的空间。这对于大部分题都是无法忍受的。
所以考虑动态开点。一般的线段树,对于节点 ,其 一般都是 ,,而这里我们直接定义两个数组 , 来表示节点 的左右儿子。
那么这样,我们会建出 个叶子结点,而对于每一个叶子结点往上还有 的深度,所以总的空间复杂度降为 。
小结:权值线段树采用动态开点以节省空间,防止序列的最大值太大导致超内存。
考虑如何用代码实现建树的过程:
inline void pushup(int p){
tr[p]=tr[ls[p]]+tr[rs[p]];
return;
}
inline void update(int &p,int l,int r,int now){
if(!p)p=++id;
if(l==r){
tr[p]++;
return;
}
int mid=(l+r)>>1;
if(now<=mid)update(ls[p],l,mid,now);
else update(rs[p],mid+1,r,now);
pushup(p);
return;
}
我们可以实现在 的过程用中 。
我们将 传参,若 未出现过则直接用 来新建节点。
表示当前节点所代表的的区间。 表示当前 往权值线段树中加入的值,那么我们就在对于包含 的全部区间上的值都加一。
剩下的部分在例题中具体实现。
二、例题
- 逆序对
相信大家都做过。
那么考虑使用权值线段树解法。
求逆序对,从左往右遍历数组,遍历到 时,检查一下已经遍历的值 中,有多少比它大的即可。
这可以用权值线段树来实现。
分类:
线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2018-04-21 一张图看懂天津市教育云服务平台
2015-04-21 MYSQL 的异常CRASH事件处理
2013-04-21 [转载]PostgreSQL学习手册(目录)