Codeforces 482B 线段树与离线区间加和问题

来源:互联网 发布:js加载div 编辑:程序博客网 时间:2024/06/06 10:01

题目大意是说,请你构造一个长度为n的数列,满足给定的m个条件,每个条件都要求从第Li个数一直and到第Ri个数的结果必须为Qi。如果存在,输出任意一组解,否则输出NO。

通过观看样例,我们很容易知道什么时候没有解:当你已经指定一个区间的某一位全都为1之后,又说他们里面至少有1个0,就没戏了。所以,很自然的想法就是:维护30个数组,每一个数组保存的都是对应二进制位的情况,每来一个条件,就把这个条件的那个Q拆成二进制,然后对于每一个是1的位,都将那一位所对应的数组里面Li~Ri涂成1,如果是0,就检查这个区间内是否都被染成1了。

但是这样做有个问题:对于某一位,如果先要求它至少有一个0,后要求全是1,你就判断不出来了。所以,我们可以把所有的要求都存起来,先对所有1染色,0不管,然后再来一遍单独检查所有0位.

这个看起来很像线段树——只要用30棵线段树就好了;但是构造解的时候就比较麻烦,因为复杂度是30 x nlogn的,10w的数据量只有1s,肯定会T。


这个时候,有两种解决问题的方法:

首先,我们注意到只有在最后我们会询问每个数的每一位是否为1,而且我们中间绝对不会把一个已经是1的数改成0.这就是一个经典的离线区间加和问题.

离线区间加和问题是说,如果我们希望把一段区间[k1,k2]加上某一个数p,那么我们可以维护一个delta[]数组,执行这个操作的时候,让delta[k1] += p, delta[k2+1] -= p。之后,我们用一个指针i扫一遍delta数组,每移动到一个地方当前值now就先加上delta[i],然后此时now的值就是正确的值了。本题也可以这样做,这样我们就可以不必构造线段树就求出每个数最后是多少;

但是还有个问题就是现在我们不能判断YES和NO。注意到判断NO其实就是询问一段区间内是不是至少有一个0,那么我们干脆预处理一下好了,用前缀和记录一下前i个now值里面0的个数,这样询问的时候直接就出来了。

复杂度是30xN,几乎是线性的……我最后用的是这种方法。


另一种方法是,不要维护30棵线段树,一棵就够了。注意到当我们增加一个新的条件时,要想满足这个条件,必要条件是这个条件里每个为1的位,现在都得为1.于是,我们可以在线段树上把那个区间的and之和 or 一下新来的这个数,然后向上更新,维护区间的and之和。最后,查询一下每个数,并检验一下是否满足所有的条件就可以了。

0 0
原创粉丝点击