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)\),可以通过。

浙公网安备 33010602011771号