提供一种需要卡常的分块写法。

首先看到 popcount 操作,便可以自然而然的想到在值域上做文章。

首先因为 \(popcount(x) \leq \log x\)

所以可以想到对于一个序列来说,进行一次 popcount 操作后至多有 \(\log V\) 个不同的数字。

并且在对这个区间进行全局操作时不同数的数量不增

因此考虑分块。

块内最开始用 tag 记录加法操作。

对于块内如果有整块 popcount 操作则转换成 pair 记录每个值都变成了什么。

类似于阈值分治的思想,不同类型的数据不同处理。

这样做复杂度是 \(O(q \sqrt n \log V)\)

会 T 得很惨。

不过还能改进。

这样做在保持分块的情况下不会写线段树的标记只能改进 popcount

所以我们用 __builtin_popcounll 函数。

所以我们这样写:

inline int popcount(int n){    return __builtin_popcountll(n);}

如此再加上一定卡常就可以过了。

代码比较丑,我贴一个剪切版在这:代码

不过这样为什么可以过呢?

因为这个函数内部用自带的表以及二分实现,虽然都是 \(\log\) 量级,但是二分理论上很难跑满。