JZOJ 4711 Binary【NOIP2016提高A组模拟8.17】

Binary

题目描述

这里写图片描述

数据范围

这里写图片描述

题解

看到数据范围这里写图片描述
这暗示着我们要把 ai 拆成20位的二进制来做。
如果 ai 化成二进制后第j位上是1,那么必满足
2j <= ai mod 2j+1 <= 2j+1 - 1 (显然,想一想不等式代表的含义就知道为什么,请读者自行思考)

询问时就是问有多少个ai满足 2j <=( ai + x ) mod 2j+1 <= 2j+1 - 1
也就是问有多少个ai满足- x +2j<= ai mod 2j+1 <=- x +2j+1- 1 (暂且不算不等式两边的值为负数的情况)
那么对答案的贡献就为满足上述不等式的ai的个数 kj 乘上 2j
kj 怎么算呢?
kj 也就等于满足 ai mod 2j+1 <=- x +2j+1- 1 ai个数减去满足 ai mod 2j+1 <- x +2j ai 个数。
这个可以种20棵树状数组来维护。

那接下来剩下的问题就是不等式两边的值为负数的情况。
首先,有一个数 u u and 2i 的运算结果是随着 u 的增长循环出现,2i个0和 2i 个1轮流出现。
因为有可循环性,所以我们可以像下图一样处理:
这里写图片描述
被圈住的区间是生效的区间,如果过了界就把过界区间往后面放,再求相应区间的答案就可以了。

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.
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值