CC's

Back

给出A1,,AnA_1, \cdots, A_n。每次询问一个区间,求该区间的子区间的[与]^(&)分别有多少不相同结果。

询问强制在线。

Ai<230A_i < 2^{30}

分析#

第一个要解决的问题是如何找到不相同的结果。根据与的性质,如果固定一个左端点(或者右端点),我们最多也就拿到30种不同的取值(每一位成0后不再变化)。第一步是把这些取值全部求出来。只要记录一下从哪一个AA起,二进制位第ii位发生了变化即可。这样拿到的结果就是形如(i,j)(i,j)表示以第ii个为左端点,在第jj个时结果发生了一次变化。对于一个固定的i来讲,j一定是升序的。

每次查询时查询对于[l,r][l,r],有多少个(i,j)(i,j)满足il,jri\geq l,j\leq r。这个时候可以考虑二维偏序的一般套路。第1维表示ii,从末尾枚举到开头,保证第一维偏序,第二维通过数据结构去维护。对于这道题来讲,每一个jj都表达了一次值的突变,所以我们就是去查对应区间中包含了多少个jj。然而这样有个问题,这个不同只是针对固定ii来讲的,对于不同的ii可能相互有一样的值。……这个转化套路我第一次听说,就是对于任意两个相同值的相邻突变点jj,插入一个新的贡献-1,从而把重复的一个减掉。

如果是离线的话到现在就已经做完了,强制在线多出来一些额外的问题。需要把第一维也扔进数据结构里维护才可以。一番查找后我了解到了主席树(心碎)。

xjb理解来说,可持久化线段树能够保存每次修改时的线段树版本——倒不如说可持久化就是指的这个特性。而利用这个特性我们可以完成这道题的要求。仍旧采用一样的枚举顺序和更新策略,并且保存下每一位更新后的历史版本,每次查询到对应的历史版本里去查即可。

想象一下最暴力的做法,我对于每个后缀ii都维护一个线段树,除了空间爆炸、时间爆炸之外,其他都挺好。可持久化线段通过一些手段,使得新版本能够利用旧版本已有的节点来优化时空占用。具体是对于一次修改操作,它最多会影响一条链上的节点,而其他部分保持不变,所以我们可以每次只创建一条新的链。

自己yy了份板子。

看起来和一般的线段树没啥大区别,至少对这道题来讲。

代码#

[牛客多校5] Interval
https://astro-pure.js.org/blog/problem-interval
Author Cheng Chen
Published at 2020年7月27日
Comment seems to stuck. Try to refresh?✨