梦熊NOIP公开赛 阈值报警色(alarm) 题解

题意简述

我们给定一个长度为\(n\)的颜色序列\(a\),颜色由\([1,m]\)构成,对于任意的颜色\(i\),\(t_i\)为这个颜色的报警阈值。对于\(a\)的一个连续区间,诺颜色\(c\)在其中出现了不少于\(t_c\)次,则触发这个颜色的报警。一个连续区间的报警色为所有出发报警的颜色中的最小值。诺没有颜色触发,则为\(m+1\). 现在对于\(i \in [1,m+1]\)求出报警色为\(i\)的区间数量

\(1 \leq n,m \leq 2 \times 10^5\)

思考

我们考虑枚举区间的右端点,显然,随着左端点的左移,去见的报警色单调不下降。

暴力做法是我们枚举左端点,使用权值线段树维护最小报警值。时间复杂度\(O(n^2log_2n)\) 预计得分\(30pts\)

我们考虑怎么优化计算。

我们依旧固定右端点。

我们考虑对每个颜色和出现的位置排序。

然后我们可以知道对于一个右端点,每个颜色第一次达到报警阈值的位置。

对于右端点\(r\),我们记颜色\(c\)第一次报警的位置为\(f_c(r)\)

我们考虑什么情况下一个颜色会成为去见的报警色。

对于颜色\(c\),但且仅当

\[\forall i \in [1,c), f_i(l)<f_c(l) \]

的时候这个颜色会产生报警

但是着设计决策,我们如果挨个判断太麻烦了。

然后我们考虑怎么维护每个位置的实际报警颜色。

我们每次右断点的移动,只会影响一个\(f_c(r)\)

由于我们有区间的报警颜色单调不下降。那么我们考虑线段树维护报警的颜色。

那么显然,我们可以通过计算这个右端点的颜色的最近更新位置\(f_{a[r]}(r)\),然后让线段树\(f_{a[r]}(r)\)往左的位置全部对\(a[r]\)取更小值。 然后由于右端点固定的时候左端点的报警颜色单调下降,所以修改的区间是连续的,然后我们就可以使用二分确定修改位置,然后线段树修改了。

但是我们怎么知道每个颜色出现的次数呢?着不是还得照着原来的扫描吗?

那么我们考虑换个角度,既然我们是关于颜色的查询,那么我们就维护关于颜色的线段输。

我们考虑线段数维护每个颜色在固定右端点时的最小左端点。

但是由于我们肯定不能说是每次都对每个颜色进行统计。

那么我们考虑维护每个右端点时的最小左端点的和。

然后我们考虑怎么更新。但是问题在于这个单调性被破坏了。

posted @ 2026-11-02 12:37  txp2025  阅读(3)  评论(0)    收藏  举报