Skip to content

Commit c7a6ec4

Browse files
committed
add rangeMex
1 parent ec9fb5a commit c7a6ec4

File tree

1 file changed

+61
-3
lines changed

1 file changed

+61
-3
lines changed

copypasta/fenwick_tree.go

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package copypasta
22

3+
import "sort"
4+
35
/* 树状数组(Fenwick Tree),二叉索引树(Binary Index Tree, BIT)
46
https://en.wikipedia.org/wiki/Fenwick_tree
57
树状数组的基本用途是维护序列的前缀和
@@ -57,14 +59,16 @@ func fenwickTree(n int) {
5759
// 求权值树状数组第 k 小的数(k > 0)
5860
// 这里 tree[i] 表示 i 的个数
5961
// 返回最小的 x 满足 ∑i=[1..x] tree[i] >= k
60-
// 思路类似倍增的查询,不断寻找 ∑<k 的数,最后+1就是答案
62+
// 思路类似倍增的查询,不断寻找 ∑<k 的数,最后 +1 就是答案
6163
// https://oi-wiki.org/ds/fenwick/#tricks
6264
// https://codeforces.com/blog/entry/61364
6365
// https://codeforces.com/problemset/problem/1404/C
6466
// todo https://codeforces.com/contest/992/problem/E
67+
// 二分 https://www.luogu.com.cn/problem/P4137
68+
// - 代码见下面的 rangeMex
6569
kth := func(k int) (res int) {
66-
const mx = 17 // bits.Len(uint(n))
67-
for b := 1 << (mx - 1); b > 0; b >>= 1 {
70+
const log = 17 // bits.Len(uint(n))
71+
for b := 1 << (log - 1); b > 0; b >>= 1 {
6872
if next := res | b; next < len(tree) && k > tree[next] {
6973
k -= tree[next]
7074
res = next
@@ -104,6 +108,7 @@ func fenwickTree(n int) {
104108
// 如果 a 范围较大则需要离散化(但这样还不如直接用归并排序)
105109
// 扩展 https://codeforces.com/problemset/problem/362/C
106110
// 环形最小逆序对 https://www.luogu.com.cn/problem/solution/P2995
111+
// 扩展:某些位置上的数待定时的逆序对的期望值 https://codeforces.com/problemset/problem/1096/F
107112
cntInversions := func(a []int) int64 {
108113
n := len(a)
109114
tree := make([]int, n+1)
@@ -130,6 +135,59 @@ func fenwickTree(n int) {
130135
_ = []interface{}{add, sum, query, addRange, kth, init, cntInversions}
131136
}
132137

138+
// 给一个数组 a 和一些询问 qs,对每个询问计算 mex(a[l..r])
139+
// a[i]>=0, 1<=l<=r<=n
140+
// 遍历数组 a,记录 a[i] 最后一次出现的位置 lastPos 以及上一个 a[i] 的位置 prevPos
141+
// 建立一个权值树状数组,维护 lastPos[v] 的前缀最小值
142+
// 树状数组维护前缀最小值的条件是每次修改只能往小改,那么从后往前做就好了
143+
// 将询问 qs 离线:按照右端点排序(或分组)
144+
// 对于一个固定的 r,我们需要查询大的数 t,使得 min{t[}
145+
// https://www.luogu.com.cn/problem/P4137
146+
// LC周赛258D https://leetcode-cn.com/problems/smallest-missing-genetic-value-in-each-subtree/
147+
// - 需要将 a 转换成 DFS 序且从 0 开始,同时最终答案需要 +1
148+
func rangeMex(a []int, qs []struct{ l, r, i int }, min func(int, int) int) []int {
149+
const mx int = 1e5 + 2
150+
tree := [mx]int{}
151+
for i := range tree {
152+
tree[i] = 1e9
153+
}
154+
update := func(i, v int) {
155+
for ; i < mx; i += i & -i {
156+
tree[i] = min(tree[i], v)
157+
}
158+
}
159+
query := func(l int) (res int) {
160+
const log = 17 // bits.Len(uint(mx))
161+
for b := 1 << (log - 1); b > 0; b >>= 1 {
162+
if next := res | b; next < mx && tree[next] >= l {
163+
res = next
164+
}
165+
}
166+
return
167+
}
168+
169+
n, m := len(a), len(qs)
170+
prevPos := make([]int, n)
171+
lastPos := make([]int, mx)
172+
for i, v := range a {
173+
prevPos[i] = lastPos[v]
174+
lastPos[v] = i + 1
175+
}
176+
for i, p := range lastPos {
177+
update(i+1, p)
178+
}
179+
180+
ans := make([]int, m)
181+
sort.Slice(qs, func(i, j int) bool { return qs[i].r > qs[j].r })
182+
for i, qi := n-1, 0; i >= 0; i-- {
183+
for ; qi < m && qs[qi].r == i+1; qi++ {
184+
ans[qs[qi].i] = query(qs[qi].l)
185+
}
186+
update(a[i]+1, prevPos[i])
187+
}
188+
return ans
189+
}
190+
133191
// 结构体写法
134192
type fenwick struct {
135193
tree []int64

0 commit comments

Comments
 (0)