【NOIP2016提高A组模拟8.17】Binary

55 篇文章 0 订阅
44 篇文章 0 订阅

Description

这里写图片描述

Input

n,q
接下来n个数a[i]
接下来询问如题目

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

n,q<100000,a[i]< 220

Solution

看题,显然二进制,然后线段树,然后就解决了?
发现区间永远是1到n,那就不是线段树
而要支持区间加,那就用树状数组
对于每一位,分别%,然后加入树状数组
询问时将x移到外面,即减完后才到树状数组里求解

Code

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 101000
#define M 1048576
#define lowbit(x) (x&(-x))
#define ll long long
using namespace std;
int n;
ll a[N],t[21][2048576];
void add(int b,int x,ll y){for(;x<=M;x+=lowbit(x)) t[b][x]+=y;}
void put(int a,ll y){fo(i,1,20) add(i,a%(1<<i)+1,y);}
ll sum(int b,int x){ll y=0;for(;x>0;x-=lowbit(x)) y+=t[b][x];return y;}
int main()
{
    int ac;scanf("%d%d",&n,&ac);
    fo(i,1,n) scanf("%lld",&a[i]),put(a[i],1);
    for(;ac;ac--)
    {
        int opt,x,y;scanf("%d%d%d",&opt,&x,&y);
        if(opt==1) put(a[x],-1),put(y,1),a[x]=y;
        else
        {
            ll ans=0;
            fo(i,1,20)
            if((y&(1<<(i-1)))>0)
            {
                int l=(1<<(i-1))-x,r=(1<<i)-x-1,jy=(1<<i);
                l=(l%jy+jy)%jy;r=(r%jy+jy)%jy;
                if(l>r) ans+=(ll)(sum(i,jy+1)-sum(i,l)+sum(i,r+1))*(ll)(1<<(i-1));
                else ans+=(ll)(sum(i,r+1)-sum(i,l))*(ll)(1<<(i-1));
            } 
            printf("%lld\n",ans);
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值