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

Problem

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

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

Data Constraint

这里写图片描述

Solution

当x=0的时候,我们只要储存每一个位置上共有几个A[i]在此位上是1.然后每一个询问y,将他们拆开,如果第i位是1, ans+=1A[i]2i1
继续。我们发现如果A[i]对答案有贡献(假设做到第j位),那么 2jA[i]Mod2j+12j+11 .
所以,如果加上一个x,那么就要满足 2jA[i]Mod2j+1+x2j+11 ,整理后,得

2jxA[i]Mod2j+12j+11x

所以我们建很多个线段树组,第i个记录 A[i]Mod2i 的有多少个。
ll=2jx,rr=2j+11x
那么答案显然是 [ll,rr]
这里写图片描述
但有可能出现 2jx<0 的情况。(即ll>rr)
这里写图片描述
ll=((x+2j)Mod2j+1+2j+1])Mod2j+1
rr=((x+2j+11)Mod2j+1+2j+1)Mod2j+1

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define N 1048580
#define NN 100010
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL ans,tree[21][N];
int _2[22],n,i,j,k,q,a[NN],opt,x,y;
int lowbit(int x){return x&(-x);}
void change(int p,int k,LL num)
{
    k++;
    while (k<=_2[p+1])
    {
        tree[p][k]+=num;
        k+=lowbit(k);
    }
}
LL find(int p,int k)
{
    int sum=0;
    k++;
    while (k)
    {
        sum+=tree[p][k];
        k-=lowbit(k);
    }
    return sum;
}
int main()
{
    _2[0]=1;
    fo(i,1,20) _2[i]=_2[i-1]*2;
    scanf("%d%d",&n,&q);
    fo(i,1,n) scanf("%d",&a[i]);
    fo(i,1,n)
        fo(j,0,19) change(j,a[i]%_2[j+1],1);
    fo(i,1,q)
    {
        scanf("%d%d%d",&opt,&x,&y);
        if (opt==1)
        {
            fo(j,0,19) change(j,a[x]%_2[j+1],-1);
            fo(j,0,19) change(j,y%_2[j+1],1);
            a[x]=y;
        } else
        {
            ans=0;
            int ll,rr;
            fo(j,0,19)
            {
                if (_2[j]&y)
                {
                    ll=((-x+_2[j])%_2[j+1]+_2[j+1])%_2[j+1];
                    rr=((-x+_2[j+1]-1)%_2[j+1]+_2[j+1])%_2[j+1];
                    if (ll<=rr)
                    {
                        ans+=_2[j]*find(j,rr);
                        ans-=_2[j]*find(j,ll-1);
                    } else
                    {
                        ans+=_2[j]*find(j,_2[j+1]-1);
                        ans-=_2[j]*find(j,ll-1);
                        ans+=_2[j]*find(j,rr);
                    }
                }
            }
            printf("%lld\n",ans);
        }
    }
}

——2016.8.17

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值