Binary
题目描述
数据范围
题解
看到数据范围,
这暗示着我们要把
ai
拆成20位的二进制来做。
如果
ai
化成二进制后第j位上是1,那么必满足
2j
<=
ai
mod
2j+1
<=
2j+1
-
1
(显然,想一想不等式代表的含义就知道为什么,请读者自行思考)
询问时就是问有多少个
也就是问有多少个
那么对答案的贡献就为满足上述不等式的
那
kj
怎么算呢?
kj
也就等于满足
ai
mod
2j+1
<=-
x
+
这个可以种20棵树状数组来维护。
那接下来剩下的问题就是不等式两边的值为负数的情况。
首先,有一个数
u
,
因为有可循环性,所以我们可以像下图一样处理:
被圈住的区间是生效的区间,如果过了界就把过界区间往后面放,再求相应区间的答案就可以了。
Code(Pascal)
var
ans:int64;
m2:array[0..20] of int64;
n,q,i,j,l,o,p,op,ll,rr:longint;
a:array[0..200000] of longint;
tr:array[0..20,0..2000000] of int64;
k:array[0..20] of longint;
procedure zj(o,lyh:int64);
var
i:longint;
begin
for i:=0 to 20 do
if o and m2[i]>0 then k[i]:=k[i]+lyh;
end;
function lowbit(o:longint):longint;
begin
exit(o and (-o));
end;
function find(p,l,r:longint):int64;
var
uu:int64;
begin
inc(r);
uu:=0;
while r>0 do
begin
uu:=uu+tr[p,r];
r:=r-lowbit(r);
end;
while l>0 do
begin
uu:=uu-tr[p,l];
l:=l-lowbit(l);
end;
exit(uu);
end;
procedure zj(p,cty,k:longint);
begin
inc(cty);
while cty<=m2[p+1] do
begin
tr[p,cty]:=tr[p,cty]+k;
cty:=cty+lowbit(cty);
end;
end;
begin
readln(n,q);
m2[0]:=1;
for i:=1 to 20 do
m2[i]:=m2[i-1]*2;
for i:=1 to n do
read(a[i]);
for i:=1 to n do
for l:=0 to 19 do
zj(l,a[i] mod m2[l+1],1);
for i:=1 to q do
begin
readln(op,o,p);
if op=2 then
begin
ans:=0;
for l:=0 to 19 do
if p and m2[l]>0 then
begin
ll:=((-o+m2[l]) mod m2[l+1]+m2[l+1]) mod m2[l+1];
rr:=((-o+m2[l+1]-1) mod m2[l+1]+m2[l+1]) mod m2[l+1];
if ll>rr then ans:=ans+(find(l,0,rr)+find(l,ll,m2[l+1]-1))*m2[l]
else ans:=ans+find(l,ll,rr)*m2[l];
end;
writeln(ans);
end
else
begin
for l:=0 to 19 do
begin
zj(l,a[o] mod m2[l+1],-1);
zj(l,p mod m2[l+1],1);
end;
a[o]:=p;
end;
end;
end.