一般来说,遇到 区间 && max_xor ,考虑 trie 板子就好了
但这道题不太像板子。。。
但可以把它变成 板子 ,
考虑一个点作为最大点的左右边界,现在我们只考虑这个区间 :
对于操作 1 :
我们固定左区间,然后枚举右区间的数值,
令数组 s[i][j] 为 截止到第i个数的第j位为1 的个数的总和
那我们就很容易得到 一个右区间的数 对于左区间的 贡献值
最后求 sum 再乘区间最大值即可。
对于操作 2 :
我们依旧固定左区间 ( 该操作在trie上实现 ) ,枚举右区间的数值
然后找 xor 大于最大值的方案数 ,
建trie的时候有一个小细节,
观察代码
int pos=0,ans=0;
for(re int i=21;i>=0;i--) {
if((y>>i)&1) {
if(pos+bin[i]>x) {
(ans+=w[tre[l][0]]-w[tre[r][0]])%=mol;
l=tre[l][1];
r=tre[r][1];
}
else {
l=tre[l][0];
r=tre[r][0];
pos+=bin[i];
}
}
else {
if(pos+bin[i]>x) {
(ans+=w[tre[l][1]]-w[tre[r][1]])%=mol;
l=tre[l][0];
r=tre[r][0];
}
else {
l=tre[l][1];
r=tre[r][1];
pos+=bin[i];
}
}
}
return ans;
我们在查找的时候如果从小的二进制位向大的二进制位查找的话,难免会遗漏一些情况, 所以我们在建树的时候就从大的二进制位向小的二进制位枚举,查找的时候依旧如此for(re int i=21;i>=0;i--)。
就好像填玻璃瓶,如果先装沙子再装石头,那怎么填满呢?
这里我们先填满石头,再装沙子填缝隙,自然就可以找全了。
最后我们把小问题合并,就成了这道题的解题思路。
枚举数轴上的数值,找它作为最大值的区间的左右边界( 可以用单调队列实现 ), 针对每个区间进行求值 ,最后综合答案 , 交卷 。
一个小优化 , 在query区间时,哪边的长度大就固定哪边。
rp++;
/ / ZJX_LM / /