【JZOJ 4711】Binary

Description

这里写图片描述

Solution

比赛的时候想了半天的线段树,结果发现....

有结论:
当y的第i位为1,并且:

2i(a+x)mod2i+12i+11

时,a的第i位二进制有效,
移项:
x=xmod2i+1
2ix(amod2i+1)2i+11x

再判断一下中间项超出模时的情况,
所以对于所有数的每位二进制,只要统计在 [2ix2i+11x] [2ix2i+11x] 这两个区间的合法个数即可判断此二进制位合法的个数,
修改就直接修改,
这个可以用树状数组来做,。
复杂度: O(nlog2(n))

Code

#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define NX(q) ((q)&(-q))
using namespace std;
typedef long long LL;
const int N=100500,M=20,M1=1<<M;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n;
LL ans;
int a[N];
int er[M+3];
int f[M+3][M1+1];
int min(int q,int w){return q<w?q:w;}
void change(int E,int q,int e){q++;while(q<=M1)f[E][q]+=e,q+=NX(q);}
int find(int E,int q)
{
    int ans=0;q++;q=min(q,M1);
    while(q>0)ans+=f[E][q],q-=NX(q);
    return ans;
}
int main()
{
    er[1]=1;fo(i,2,M+2)er[i]=er[i-1]<<1;
    int q,w,e;
    read(n),read(m);
    fo(i,1,n)
    {
        read(a[i]);
        fo(j,1,M)change(j,a[i]%er[j+1],1);
    }
    fo(i,1,m)
    {
        read(q),read(w),read(e);
        if(q==1)
        {
            fo(j,1,M)if((a[w]%er[j+1])!=(e%er[j+1]))change(j,a[w]%er[j+1],-1),change(j,e%er[j+1],1);
            a[w]=e;
        }
            else
            {
                ans=0;
                fo(i,1,M)if(er[i]&e)ans+=(LL)er[i]*(find(i,er[i+1]-1-w%er[i+1])-find(i,er[i]-1-w%er[i+1])+find(i,er[i+1]+er[i+1]-1-w%er[i+1])-find(i,er[i+1]+er[i]-1-w%er[i+1]));
                printf("%lld\n",ans); 
            }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值