算法 {权值线段树}
权值线段树
定义
#问题背景#
给定&S: 数的集合(去重)
; 令&Cont[]: 每个数出现的次数 最初全为0
;
操作1-修改: 给定x \in &S
和c: 个数
, 表示执行Cont[x] += c
; (即添加/去除若干个该数);
操作2-查询: 给定l<=r
, 求Cont[l...r]之和
以及他们的Cont[i]*i
之和;
#分析#
&S
可以很大 比如[-2e9, 2e9]
范围 但她的大小 比如只有N=1e6
个数; 因此 进行离散化哈希, 即线段树区间是[0, N)
;
线段树里存Count, Sum
, 修改时: (叶子节点):Count += c; Sum += (c * Hash.Map[ ind])
;
查询时: 令L,R
是[l,r]
所包含的出现在&S
里面的数的 离散化值, 那么查询线段树[L-R]
区间即可;
性质
如果操作1是 区间修改, 使用懒标记应该是可以的(还没遇到…)
算法
模板
使用线段树:
#Merge#
Count = _lef.Count + _rig.Count;
Sum = _lef.Sum + _rig.Sum;
#Modify_index#(叶子节点)
info.Count += _modVal;
info.Sum += (_modVal * 1LL * Hash.Map.at( info.Interval.first));
求任意子區間的第K小數
@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=135329076
;
应用
@LINK: https://atcoder.jp/contests/abc351/tasks/abc351_f
;
模板题;
笔记
#定义#
给定数组A[N]
; (如果是朴素线段树 那么其底层数组长度就是N
);
1: 将A进行离散化哈希成[0,Range)
(當然 如果min(A)>=0 && max(A)不大
不用進行離散化 即此時Range== max(A)
);
2: 線段樹的底層數組長度是Range
(比如線段樹的某個葉子節點[x]
那麼他就對應A裡面離散哈希值等於x
的元素);
.
比如A=[33,11,11,44]
離散化後是[1,0,0,2]
, 即線段樹的底層數組長度是3
比如葉子節點[0]
她的Count
值會是2
(表示11
這個數 有2
個);
@DELI;
#性質#
對於A[N]
你修改他們的元素次序 (比如A= [3,2,1] / [2,1,3] / [1,3,2]
), 則他們對應的權值線段樹 是一樣的;