Jzoj4711 Binary

如果没有这个+x的话应该都能想到是按位拆开每一位处理吧

现在考虑这个+x如何处理

一个数v加上x,如果有(v+x)%2^i>2^(i-1)的话,那么就必然第i位为1

所以我们考虑,对于每一个询问的y,若有y&(1<<i)为true,就将所有的数mod (1<<i+1)的值在区间[2^i-x,2^(i+1)-1-x]的个数统计出来,让后乘上2^i就是这一位的贡献,注意特殊处理一下,因为x是在mod (1<<i+1)的意义下的,所以有可能右端点在左端点左边,这时候要拆开来统计

具体实现可以用fenwick树

(一个小小的常熟优化,不要用%2^i而要用&(2^i-1))

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define f(k) (1ll<<k)
#define g(k) (f(k+1)-1)
using namespace std;
int w[22][1<<20],n,m,v[100010];long long A=0;
inline void add(int i,int x,int k){ for(++x;x<=f(i+1);x+=x&-x) w[i][x]+=k; }
inline int sum(int i,int x,int s=0){ for(++x;x;x^=x&-x) s+=w[i][x]; return s; }
int main(){
	scanf("%d%d",&n,&m);
	for(int x,i=1,j;i<=n;++i){
		scanf("%d",v+i);
		for(int j=0;j<20;++j) add(j,v[i]&g(j),1);
	}
	for(int o,x,y;m--;){
		scanf("%d%d%d",&o,&x,&y);
		if(o==1){
			for(int j=0;j<20;++j)
				add(j,v[x]&g(j),-1),add(j,y&g(j),1);
			v[x]=y;
		} else {
			A=0;
			for(int j=0;j<20;++j) if(y&f(j)){
				int l=f(j)-1,r=g(j);
				l=(l-x+f(20))&g(j);
				r=(r-x+f(20))&g(j);
				if(l<=r) A+=f(j)*(sum(j,r)-sum(j,l));
				else A+=f(j)*(sum(j,r)+sum(j,f(j+1))-sum(j,l));
			}
			printf("%lld\n",A);
		}
	}
}

posted @   扩展的灰(Extended_Ash)  阅读(99)  评论(0编辑  收藏  举报
编辑推荐:
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
阅读排行:
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单
点击右上角即可分享
微信分享提示