P11398 众数

P11398 众数

题目描述

你有 \(n\) 个数对 \((a_1,b_1),\ldots,(a_n,b_n)\)

定义下标 \(i(1\le i\le n)\) 的权值为将 \(a_1\)\(b_1\)\(a_2\)\(b_2\),...,\(a_i\)\(b_i\) 拼接在一起后形成的数组的最大众数(特别地,若所有数出现次数相同则为最大数)乘以 \(a_i\)

接下来你有 \(m\) 个操作,分两种:

  • 1 x y,将 \(a_x\) 增加 \(y\)保证 \(y\) 非负。
  • 2 q,求最小的正整数 \(k\) 使得下标 \(n-k+1 \sim n\) 的权值异或和为 \(q\)

2 操作保证有解,且所有答案之和(记为 \(\sum k\))不超过 \(5\times 10^7\)

题解

先转化问题,我们肯定要枚举 \(k\) 然后求答案,问题就在于怎样快速求出前缀的众数。

Subtask 1~9

我们可以每一次修改的时候暴力修改每个位置上的前缀信息,然后众数就可以直接 \(O(1)\) 维护出来了。复杂度为 \(O(nm+\sum k)\)

对于没有修改操作的点,预处理出众数后就不用动了,复杂度 \(O(n+\sum k)\)

Subtask 10~15

前三个包的 \(b_i\) 很小,我们要维护的就是前缀 \(1\) 和前缀 \(2\) 的个数,比较这两个的大小即可。如果用树状数组维护的话 \(\sum k\) 上要带一个 \(\log\),不能承受。注意到我们的 \(k\) 是从后往前枚举的,因此我们可以考虑每次动态从全局的信息中删除当前点的贡献,这样就可以 \(O(1)\) 维护当前 \(1,2\) 的个数。复杂度 \(O(n+m+\sum k)\)

对于 \(b_i\) 较大的情况,我们不得不使用线段树来删除贡献,同时还需要维护全局 \(\max\),复杂度是 \(O((n+m+\sum k)\log n)\)。可以通过 Subtask 13~15。

Subtask 16~19

此时我们只关心后 \(300\) 个点的信息,一种办法是沿用暴力的做法,不过单次只修改这 \(300\) 个点的信息,复杂度 \(O(300m+\sum k)\)。不过这对正解没有什么启发。

考虑众数这个信息是容易加入但不容易删除的,我们之前的所有枚举都基于从后往前枚举前缀,这必然涉及到删除操作。那么考虑倒过来,从 \(n-300\) 开始向 \(n\) 枚举,每次动态加入一个点并维护众数,最后暴力求出后 \(300\) 个点的权值然后求答案即可。而我们要维护的信息只有前 \(n-300\) 个点的信息,单次修改 \(O(1)\) 即可,复杂度不变。

Subtask 20~25

我们现在的做法基于从前往后枚举,如果每次从 \(1\) 开始枚举接受不了。考虑分块,从后往前枚举每个块,块内按照上面的方式从前往后枚举求答案。此时我们需要维护 \(O(\sqrt n)\) 个前缀的信息,单次修改 \(O(\sqrt n)\);查询的时候我们的复杂度应该是 \(O(k+\sqrt n)\) 的,所以总复杂度为 \(O((n+m)\sqrt n+\sum k)\)

这个做法还是不够优秀,很显然这个块长还是浪费的比较多。考虑倍增,我们把块长改为 \(2^0,2^1,2^2,\cdots\),这样的话我们要维护的只有 \(O(\log n)\) 个前缀信息,同时单次查询复杂度为 \(O(k+\log n)\),所以总复杂度为 \(O((n+m)\log n+\sum k)\),可以通过。

posted @ 2026-03-02 08:23  UKE_Automation  阅读(13)  评论(0)    收藏  举报