前缀和神题。
在本篇文章中,
t
t
t 位是指从
2
t
2^t
2t,后
t
t
t 位是指从第
0
0
0 位到第
t
t
t 位。
对于询问
t
t
t ,只需保留后
t
t
t 位数字(保留高位不方便我们做前缀和)。
观察一下如何添加会使进位出第
t
t
t 的值为1,这里再分两种情况讨论。
将所有添加的和记为
s
u
m
sum
sum ,后
t
−
1
t-1
t−1 位值记录为
j
l
jl
jl。
1. 2 t ∧ s u m = 0 2^t \land sum=0 2t∧sum=0
这种情况就要求添加后第
t
t
t 位为1。
当
2
t
≤
x
≤
2
t
+
1
−
1
2^t\le x\le 2^{t+1}-1
2t≤x≤2t+1−1,第
t
t
t 位为1。
所以前缀和范围就是
[
2
t
−
j
l
,
2
t
+
1
−
1
−
j
l
]
[2^t-jl,2^{t+1}-1-jl]
[2t−jl,2t+1−1−jl] 。
2. 2 t ∧ s u m ≠ 0 2^t \land sum\neq 0 2t∧sum=0
这里还有细分两种情况,第一种是原先第
t
t
t 位为0,加上
s
u
m
sum
sum 的后
t
−
1
t-1
t−1 位后第
t
t
t 位进位后还是0 ,第二种是原先第
t
t
t 位为1,加上
s
u
m
sum
sum 的后
t
−
1
t-1
t−1 位后第
t
t
t 位进位后为0。
前缀和范围分别是
[
0
,
2
t
−
j
l
]
[0,2^t-jl]
[0,2t−jl] 和
[
2
t
+
1
−
j
l
−
1
,
2
t
+
1
−
1
]
[2^{t+1}-jl-1,2^{t+1}-1]
[2t+1−jl−1,2t+1−1]
第二种情况范围上限是
2
t
+
1
−
1
2^{t+1}-1
2t+1−1 是因为保留数组最高就是
2
t
+
1
−
1
2^{t+1}-1
2t+1−1 。
代码
//插入
for(int i=1;i<=n;i++) {
cin>>x;
for(int j=0;j<=15;j++)
gb(x%mi[j+1]+1,j);
}
//查询
int jl=sum%mi[x];
if(sum&mi[x]) ans+=qh(mi[x+1],x)+qh(mi[x]-jl,x)-qh(mi[x+1]-jl,x);
else ans+=qh(mi[x+1]-jl,x)-qh(mi[x]-jl,x);
//由于我用树状数组做前缀和,为了防止下标0的出现所以下标都加了1