您的位置:首页 > 其它

JZOJ4711. Binary

2016-08-17 19:52 465 查看

题目大意



Data Constraint

n,q≤105,ai<220

题解

和SCOI2016的题目有相似之处。

每一位开一个树状数组,以数轴为轴,记录只保留当前位往后的数有哪些。

对于每个询问,我们按位来统计答案,第k位对答案的贡献就是num∗(1<<k)其中num是+x后当前位为1的数的个数。

这个怎么查询呢?设当前统计第k位,之前的位置我们不需要考虑。注意到在没有+x的情况下,我们要求的数的下界是L=k10000...最高位的1是第k位的,上界是R=k11111...,现在有+x,所以真正要查询的区间是[L−x,R−x]。但是还有进位的情况,此时下界为L=k+111000...即k+1和k位都是1,其余全0,上界为R=k+111111...,k+1位全1。

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;

#define N 100000 + 10
#define M 1200000 + 10
typedef long long ll ;
const int Maxv = 1048576 ;

int T[20][M] ;
int a
;
int n , Q ;
int ret ;
ll ans ;

int lowbit( int x ) { return x & (-x) ; }

void Modify( int t , int k , int del ) {
while ( k <= Maxv + 1 ) {
T[t][k] += del ;
k += lowbit(k) ;
}
}

int Find( int t , int k ) {
int ret = 0 ;
if ( k > Maxv ) k = Maxv ;
while ( k > 0 ) {
ret += T[t][k] ;
k -= lowbit(k) ;
}
return ret ;
}

int main() {
scanf( "%d%d" , &n , &Q ) ;
for (int i = 1 ; i <= n ; i ++ ) {
scanf( "%d" , &a[i] ) ;
for (int k = 0 ; k <= 19 ; k ++ ) {
int t = (a[i] & ((1 << (k+1)) - 1)) ;
Modify( k , t + 1 , 1 ) ;
}
}
for (int i = 1 ; i <= Q ; i ++ ) {
int op , x , y ;
scanf( "%d%d%d" , &op , &x , &y ) ;
if ( op == 1 ) {
for (int k = 0 ; k <= 19 ; k ++ ) {
int t = (a[x] & ((1 << (k+1)) - 1)) ;
Modify( k , t + 1 , -1 ) ;
}
a[x] = y ;
for (int k = 0 ; k <= 19 ; k ++ ) {
int t = (a[x] & ((1 << (k+1)) - 1)) ;
Modify( k , t + 1 , 1 ) ;
}
} else {
ans = 0 ;
for (int k = 19 ; k >= 0 ; k -- ) {
if ( !((y >> k) & 1) ) continue ;
int tp = (x & ((1 << (k+1)) - 1)) ;
int L = (1 << k) - tp ;
int R = (1 << (k+1)) - 1 - tp ;
ret = Find( k , R+1 ) - Find( k , L ) ;
L = ((1 << k) | (1 << (k+1))) - tp ;
R = (1 << (k+2)) - 1 - tp ;
ret += Find( k , R+1 ) - Find( k , L ) ;
ans += (ll)ret * (1ll << k) ;
}
printf( "%lld\n" , ans ) ;
}
}
return 0 ;
}


以上.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: