binary

Description

给定一个长度为n的整数数列 a a q 次操作:
修改操作:形如 1 x y 1   x   y ,表示将 ax a x 的值改为 y y
询问操作:形如 2 x y 2   x   y ,表示询问 ni=1(ai+x) and y ∑ i = 1 n ( a i + x )   a n d   y 的值。

Input

第一行两个整数  n,q   n , q
第二行包含n个整数  ai   a i
之后  q    q   行包含三个整数  optxy   o p t , x , y

Output

对于每一个询问操作,输出一行包含一个整数,表示该询问操作的答案。

Data Constraint

n,q1000000ai,x,y<220 n , q ≤ 100000 0 ≤ a i , x , y < 2 20

Sample Input

6 6
8 9 1 13 9 3
1 4 5
2 6 9
1 3 7
2 7 7
1 6 1
2 11 13

Sample Output

45
19
21

Solution

①当 x=0 x = 0

将每一项  ai    a i   拆分成二进制,记录每一位(即 ai and 2i a i   a n d   2 i =1 = 1 的数有多少个,
如果该位如果  y    y   的第  2i    2 i   位也正好等于  1   1 ,那么将  ans    a n s    fi2i   f i ∗ 2 i

②当 x0 x ≠ 0

还是一位一位增加答案,假设现考虑第i位,则显然是 [2i , 2i+11] [ 2 i   ,   2 i + 1 − 1 ] 的数是可行的,
所以我们可以建立树状数组  ci,j    c i , j   来记录每项  a mod 2i+1   a   m o d   2 i + 1 ,但还是要对x进行讨论:
姑且将  x mod 2i+1   x   m o d   2 i + 1 先。

<1>当  x 2i   x ≤   2 i

ans  a n s   加在  [2ix , 2i+11x]    [ 2 i − x   ,   2 i + 1 − 1 − x ]   之间的数的个数 2i ∗ 2 i

<2>当 x>2i x > 2 i

ans  a n s   加在 [0 , 2i+11x]  [2i+1+2ix,2i+11]  [ 0   ,   2 i + 1 − 1 − x ]   ⋃   [ 2 i + 1 + 2 i − x , 2 i + 1 − 1 ]   之间的数的个数 2i ∗ 2 i

code

const   maxn=100005;
        w=20;
                mm=1<<20;
var     i,j,n,q,o,x,x0,y:longint;
        ans,v:int64;
        a:array[1..maxn] of longint;
        c:array[1..20,0..1200000] of int64;
procedure update(i,value,mo:longint);
begin
        if i=0 then c[mo,i]:=c[mo,i]+value else
        while(i<=mm) do begin
                 c[mo,i]:=c[mo,i]+value;
                 i:=i+i and (-i);
        end;
end;
function get(i,mo:longint):int64;
var     s:int64;
begin
        s:=0;
        while i>0 do begin
                s:=s+c[mo,i];
                i:=i-i and (-i);
        end;
        if i>=0 then s:=s+c[mo,0];
        exit(s);
end;
begin
    readln(n,q);
    for i:=1 to n do read(a[i]);
    readln;
    for i:=1 to w do
        for j:=1 to n do update(a[j] mod (1<<i),1,i);
    for i:=1 to q do begin
        readln(o,x0,y);
        if o=1 then begin
            for j:=1 to w do update(a[x0] mod (1<<j),-1,j);
            a[x0]:=y;
            for j:=1 to w do update(a[x0] mod (1<<j),1,j);
        end else begin
            ans:=0;
            for j:=1 to w do if y>>(j-1) mod 2=1 then begin
                x:=x0 mod (1<<j);
                if x<=1<<(j-1) then begin
                    v:=get(1<<j-1-x,j);
                    v:=v-get(1<<(j-1)-x-1,j);
                    v:=v*(1<<(j-1));
                    ans:=ans+v;
                end else begin
                    v:=get(1<<j-1-x,j);
                    v:=v+get(1<<j-1,j);
                    v:=v-get((1<<j)+(1<<(j-1))-x-1,j);
                    v:=v*(1<<(j-1));
                    ans:=ans+v;
                end;
            end;
            writeln(ans);
        end;
    end;
end.


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值