0%

2025 ICPC Asia Manila Regional(2025 ICPC 亚洲 菲律宾 马尼拉)——B. DJ Nicholas(get_range_cnt,可以变为 get_pref_cnt(r)-get_pref_cnt(l - 1),是一个非常经典的套路)

题目大意

题目设定
给定一个包含 kk1k261 \le k \le 26)首短歌的曲库,分别用前 kk 个大写英文字母表示。
由这 kk 首歌可以生成一个无限长的母带(master track)tt。生成方式为:不断重复这 kk 首歌,但在每一次重复整个曲库时,都会将当前序列的第一首歌移动到序列的末尾。
例如,当 k=4k = 4 时,曲库初始为 ABCD,那么母带 tt 就是无限长的字符串 ABCD BCDA CDAB DABC ABCD ...

有一个长度为 nn 的播放列表,初始时全部为空白。在此问题中,播放列表和母带均从 1 开始索引。

操作要求
需要对播放列表执行 qq 次操作,操作分为以下两种:

  1. + i a b:将播放列表中从位置 aabb(包含两端)的片段,替换为母带 tt 中从位置 ii 开始、长度为 ba+1b - a + 1 的子串。

  2. ? a b:查询播放列表中从位置 aabb(包含两端)的片段。输出 kk 个整数,其中第 jj 个整数表示该片段中第 jj 个英文字母(即第 jj 首歌)的出现次数。

输入格式
第一行包含三个空格分隔的整数 kknnqq
接下来 qq 行,每行描述一个操作,格式为 + i a b? a b

输出格式
对于每一个 ? a b 操作,输出一行包含 kk 个空格分隔的整数,表示查询的结果。

数据范围
1k261 \le k \le 26
1n1091 \le n \le 10^9
1q1051 \le q \le 10^5
每次操作中:1i1091 \le i \le 10^91abn1 \le a \le b \le n

样例输入

1
2
3
4
5
4 10 4
+ 7 2 6
+ 2 8 10
+ 9 1 4
? 4 9

样例输出

1
1 2 1 1

样例解释
在此样例中,k=4k = 4n=10n = 10。母带 ttABCDBCDACDABDABC...
播放列表初始为空,我们用星号代表空白部分:**********

  1. 执行 + 7 2 6
    我们需要一个长度为 62+1=56 - 2 + 1 = 5 的子串。
    母带 tt 中从位置 7 开始、长度为 5 的子串是 DACDA
    将播放列表中第 2 到第 6 首歌替换为该子串,此时播放列表变为:DACDA****

  2. 执行 + 2 8 10
    播放列表第 8 到 10 的位置被替换后变为:DACDA*BCD

  3. 执行 + 9 1 4
    覆盖掉前 4 个位置的歌曲,播放列表最终变为:CDABDA*BCD

  4. 执行 ? 4 9
    查看当前播放列表中第 4 到第 9 首歌,对应片段为 BDA*BC
    需要输出 A、B、C、D 四个字母在此片段内分别出现的次数。因此,输出 1 2 1 1

思路讲解

其实还是很明显的动态开点线段树。我说白了是个动态开点线段树的云玩家,我都看出来是动态开点线段树了。

P13825 【模板】线段树 1.5(指针式动态开点线段树)

既然是这个动态开点线段树,我们想一想,我们的 apply 函数如何书写吧。

其实最重要的是,在知道母带上 l,r 的情况下,求出母带上的 cnt 数组。

get_range_cnt,可以变为 get_pref_cnt®-get_pref_cnt(l - 1),是一个非常经典的套路。

1
2
3
4
5
6
7
8
array<int, 26> get_range_cnt(ll l, ll r) {
auto R = get_pref_cnt(r);
auto L = get_pref_cnt(l - 1);
for (int i = 0; i < k; ++i) {
R[i] -= L[i];
}
return R;
}

AC代码

AC
https://codeforces.com/gym/106262/submission/365836934

心路历程(WA,TLE,MLE……)

image

image

image