诈尸啦~
这篇博客是很久之前就想写的,总结一些关于区间种类数的问题,
正好一早上都在偏远机房上课,又不想写项目,就随便更新一点;
题意:
给定一个长度为
n
n
n 的序列,有
m
m
m 次操作(
n
,
m
<
=
1
e
5
n,m<=1e5
n,m<=1e5)
思路:
这个问题太复杂了,我们考虑简化问题:
只有区间种类数。
这是十分经典的问题;最典型的做法就是大家都知道的莫队做法,复杂度
O
(
n
q
)
O(n\sqrt{q} )
O(nq)的。
这里给出另一种常见的做法:通过将询问离线,把询问挂到区间右端点上,再通过记录每个元素上一次出现的位置,扫一遍序列的同时,用树状数组维护每个左端点到当前右端点
r
r
r的种类数(指针
r
r
r是不断向右移动的),扫一遍序列的同时,遇到询问就在树状数组上查询即可,复杂度
O
(
(
n
+
q
)
l
o
g
(
n
)
)
O((n+q)log(n) )
O((n+q)log(n));
哈,没想到吧,还有一种。用
p
r
e
[
]
pre[]
pre[]数组,表示上一个和当前元素相同的位置。那么想要求区间种类数,一个常见的套路是:区间中所有相同的元素,只有区间中最左边的位置做贡献。可以发现,这个位置
i
i
i 满足
p
r
e
[
i
]
<
l
pre[i]
单点修改,询问区间种类数。
可以发现,第一个问题中的第三个做法,可拓展性很强,考虑沿用这个做法。
不难发现,进行一次单点修改时,只有三个位置的
p
r
e
pre
pre值会发生变化,可以每个颜色开一个
s
e
t
set
set,那就知道是什么位置发生变化了,问题就变成了经典的带修二维数点问题。这边建议用
C
D
Q
CDQ
CDQ分治 实现,从修改对询问的影响入手,具体怎么实现,留给读者自行思考。
区间赋值,询问区间种类数。
先说结论:进行
m
m
m次区间赋值,
p
r
e
[
]
pre[]
pre[]数组的变化是
O
(
n
+
m
)
O(n+m)
O(n+m)的;
对于同一个颜色的一整块,统一赋值成另一个颜色,对于
p
r
e
pre
pre 的变化也只有三个(因为原本同色,赋值之后还是同色的,
p
r
e
[
i
]
=
i
−
1
pre[i]=i-1
pre[i]=i−1,不会发生变化);
那么这个问题中的颜色相同的一段 等于 上个问题中的一个点,从上面的证明我们知道,
p
r
e
pre
pre 的改变次数 等于 删除的点的个数;已知,原本是
n
n
n个点,一个赋值操作,最多能增加三个点(因为有可能把原本是一段的点,割开了),且每个点最多只能删除一次,那么
p
r
e
pre
pre 的变化次数就是
O
(
n
+
m
)
O(n+m)
O(n+m) 的,那么不就可以看成上一个问题,直接上
C
D
Q
CDQ
CDQ了吗!好耶!就是区间赋值会有点麻烦,上个珂朵莉加上每个颜色一个
s
e
t
set
set,就好多了~
读者自己思考尝试一下吧。
代码:
无,
可能一段时间都不想写代码了…