题目链接:https://www.nowcoder.com/acm/contest/211/E

题目描述

请实现一个数据结构支持以下操作:区间循环左右移,区间与,区间或,区间求和。

输入描述:

第一行n,q表示数列长度及操作次数。
第二行n个数表示初始序列。
接下来q行表示操作。

操作格式如下:
一行表示一个操作。所有操作形如 opt l r v。
opt=1 表示将区间[l,r]循环右移v位。
opt=2 表示将区间[l,r]循环左移v位。
opt=3 表示将区间[l,r]按位或上v。
opt=4 表示将区间[l,r]按位与上v。
opt=5 询问区间[l,r]的和。

保证opt=1或2时 1 ≤ v ≤ 20
注意:为了优化你的做题体验,操作5也会输入一个v,但是是没有意义的。
注意:循环左右移在20个二进制位的意义下进行

输出描述:

对于每个opt=5的操作,输出一个数表示答案。

输入
10 10
10112 23536 1305 7072 12730 29518 12315 3459 12435 29055
4 5 10 12373
2 1 6 7
5 4 10 24895
1 1 4 8
5 3 7 7767
5 7 9 6127
4 2 8 30971
5 4 10 2663
1 7 10 1
1 2 9 5

输出
2001530
1600111
24611
49482

备注:
1 ≤ N,Q ≤ 2*10^5 且 0 ≤ ai < 2^20
一些说明:
1. 对于00000000000000000101,右移一位后会变成10000000000000000010
2. 不是区间位移,是区间中的每一个数的二进制位的位移

题解:

(说实话这道题其实不难的,会线段树就应该想到怎么做的,可能是我脑子太笨了吧,比赛的时候想不到怎么做。)

考虑到只有二进制下只有 $20$ 位,而且修改操作都是按位与或者按位或,所以可以将 $20$ 位拆开来看。

然后就简单了呀:

  对 $01$ 序列中某一个区间,全部与上 $x(x=0,1)$,那么 $x = 1$ 时不变, $x = 0$ 时全 $0$。

  对 $01$ 序列中某一个区间,全部或上 $x(x=0,1)$,那么 $x = 0$ 时不变, $x = 1$ 时全 $1$。(这两种操作可以归结为直接把一个常见的线段树区间覆盖操作)

  循环平移就是在 $20$ 棵平衡树进行数据的循环平移,向左向右循环平移都可以全部归结为向右平移,范围为 $(0,19)$,这个就是把每个线段树节点里的二十位的01序列重新排一下即可。

  求和,我们线段树每个节点都有一个 $val[20]$ 用以为维护某一位上,当前区间内所有数字在这一位上合起来总共出现了多少个 $1$,也就是说这个 $val[20]$ 相当于一个算加法但还没来得及进位的二进制数,这样的二进制数转成十进制和普通二进制数转十进制是一样的。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+; int n,q,a[maxn]; /********************************* Segment Tree - st *********************************/
int tmp[];
struct Node{
int l,r;
int val[];
int lazy[],shft;
void upd_shft(int x)
{
x=(x+)%;
shft=(shft+x)%;
for(int i=;i<x;i++) tmp[i]=lazy[i];
for(int i=;i<-x;i++) lazy[i]=lazy[i+x];
for(int i=;i<x;i++) lazy[i+-x]=tmp[i]; for(int i=;i<x;i++) tmp[i]=val[i];
for(int i=;i<-x;i++) val[i]=val[i+x];
for(int i=;i<x;i++) val[i+-x]=tmp[i];
}
void upd_lazy(int i,int x)
{
val[i]=(r-l+)*x;
lazy[i]=x;
}
}node[*maxn];
void pushdown(int root)
{
if(node[root].shft)
{
node[root*].upd_shft(node[root].shft);
node[root*+].upd_shft(node[root].shft);
node[root].shft=;
}
for(int i=;i<;i++)
{
if(node[root].lazy[i]!=-)
{
node[root*].upd_lazy(i,node[root].lazy[i]);
node[root*+].upd_lazy(i,node[root].lazy[i]);
node[root].lazy[i]=-;
}
}
}
void pushup(int root)
{
for(int i=;i<;i++)
node[root].val[i]=node[root*].val[i]+node[root*+].val[i];
}
void build(int root,int l,int r)
{
if(l>r) return;
node[root].l=l, node[root].r=r;
node[root].shft=;
for(int i=;i<;i++) node[root].lazy[i]=-;
if(l==r)
{
for(int i=;i<;i++)
node[root].val[i]=(a[l]>>i)%;
}
else
{
int mid=(l+r)/;
build(root*,l,mid);
build(root*+,mid+,r);
pushup(root);
}
}
void update(int type,int root,int st,int ed,int x)
{
if(st<=node[root].l && node[root].r<=ed)
{
if(type==)
{
node[root].upd_shft(x);
}
if(type==)
{
for(int i=,k;i<;i++)
{
k=(x>>i)%;
if(!k) node[root].upd_lazy(i,);
}
}
if(type==)
{
for(int i=,k;i<;i++)
{
k=(x>>i)%;
if(k) node[root].upd_lazy(i,);
}
}
}
else
{
int mid=(node[root].l+node[root].r)/;
pushdown(root);
if(st<=mid) update(type,root*,st,ed,x);
if(ed>mid) update(type,root*+,st,ed,x);
pushup(root);
}
}
ll query(int root,int st,int ed)
{
if(st<=node[root].l && node[root].r<=ed)
{
ll res=;
for(int i=;i<;i++) res+=(ll)node[root].val[i]*(<<i);
return res;
}
pushdown(root);
int mid=(node[root].l+node[root].r)/;
ll res=;
if(st<=mid) res+=query(root*,st,ed);
if(ed>mid) res+=query(root*+,st,ed);
return res;
}
/********************************* Segment Tree - ed *********************************/ int main()
{
scanf("%d%d",&n,&q);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
build(,,n);
while(q--)
{
int op,l,r,v;
scanf("%d%d%d%d",&op,&l,&r,&v);
if(op==) update(,,l,r,v);
if(op==) update(,,l,r,-v);
if(op==) update(,,l,r,v);
if(op==) update(,,l,r,v);
if(op==) printf("%lld\n",query(,l,r));
}
}

nowcoder 211E - 位运算?位运算! - [二进制线段树][与或线段树]的更多相关文章

  1. 算法竞赛进阶指南--lowbit运算,找到二进制下所有是1的位

    // lowbit运算,找到二进制下所有是1的位 int H[37]; // 预处理 for (int i = 0; i < 36; i++) H[(1ll << i) % 37] ...

  2. 位运算&字节运算

  3. C#中的位的或运算的理解

    如果懂位的运算,看到下面这2个程序执行的结果,会很容易理解,如果像我这样的菜鸟,刚接触开始肯定也觉得晕晕的,|= 这是什么运算符? |=就是位的或运算符,下面还是用上面的程序来讲解一下,为什么上面2个 ...

  4. C166 8位字节位运算赋值-代码优化

    8位字节位运算赋值优化特记录下: unsigned short func1(){ unsigned short a; return a;} unsigned char func2(){ unsigne ...

  5. C++:用字符串数组实现大数运算,以两个不高于40位的大数运算为例。

    因为基本数据类型中整型的内存范围有限,所以直接进行大数之间的运算,不仅浪费空间,而且运行缓慢,甚至有些会导致数据溢出. 那怎么办呢? 这时我们就想直接不行,那咱们来间接的. 这就是我们今天主要要讲的: ...

  6. Python读字节某一位的值,设置某一位的值,二进制位操作

    Python读字节某一位的值,设置某一位的值,二进制位操作   在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fa ...

  7. JAVA如何把一个float四舍五入到小数点后2位,4位,或者其它指定位数.

    怎么使float保留两位小数或多位小数 http://meryvn.blog.163.com/blog/static/36962664201173010402629/ 两种方法: import   j ...

  8. 中国石油大学(华东)暑期集训--二进制(BZOJ5294)【线段树】

    问题 C: 二进制 时间限制: 1 Sec  内存限制: 128 MB提交: 8  解决: 2[提交] [状态] [讨论版] [命题人:] 题目描述 pupil发现对于一个十进制数,无论怎么将其的数字 ...

  9. SQLite在.NET中自适应32位/64位系统

    如果一个.NET应用要自适应32位/64位系统,只需要在项目的“目标平台”设置为“Any CPU”.但是如果应用中使用了SQLite,情况就不同了. SQLite的.NET开发包来自是System.D ...

  10. 让使用SQLite的.NET应用自适应32位/64位系统

    如果一个.NET应用要自适应32位/64位系统,只需要在项目的“目标平台”设置为“Any CPU”.但是如果应用中使用了SQLite,情况就不同了. SQLite的.NET开发包来自是System.D ...

随机推荐

  1. RabbitMQ使用技巧

    一. net客户端介绍    http://www.cnblogs.com/hsyzero/p/6297644.html 二. RabbitMQ消息应答 执行一个任务可能需要花费几秒钟,你可能会担心如 ...

  2. 湾区求职分享:三个月刷题拿到 Google offer,欢迎踊跃提问

    本文仅以个人经历和个人观点作为参考.如能受益,不胜荣幸. 本文会不断的修正,更新.希望通过大家的互动最后能写出一份阅者受益的文章. 本文纯手打,会有错别字,欢迎指出,虚心接受及时更改. 小马过河,大牛 ...

  3. Jason 和 Java 对象转化示例

    1.工程 2.代码: JsonUtil.java package com.my.json; import java.util.ArrayList; import java.util.List; imp ...

  4. github贡献开源项目

    1.正常流程 1.拷贝项目到自己的github 2.本地修改后提交远程仓库 3.创建讨论Pull requests 4.开源项目者合并到master分支 5.删除仓库 2.快速发出讨论Pull req ...

  5. GNU Binutils简介及基本用法

    [时间:2017-06] [状态:Open] [关键词:GNU, binutils, as, ld, ar, 基础工具,linux,链接器,汇编器] 0 简介 GNU Binary Utilities ...

  6. Java 同时返回多个不同类型的方法

    Java 同时返回多个不同类型的方法 2016年12月02日 16:05:07 FXBStudy 阅读数:10045   前言:虽然对于这种需求不常用,且比较冷门,但是还是有其存在的价值,再次做一下整 ...

  7. Java知多少(2)虚拟机(JVM)以及跨平台原理

    相信大家已经了解到Java具有跨平台的特性,可以“一次编译,到处运行”,在Windows下编写的程序,无需任何修改就可以在Linux下运行,这是C和C++很难做到的. 那么,跨平台是怎样实现的呢?这就 ...

  8. Java知多少(71)文件与目录管理

    目录是管理文件的特殊机制,同类文件保存在同一个目录下不仅可以简化文件管理,而且还可以提高工作效率.Java 语言在 java.io 包中定义了一个 File 类专门用来管理磁盘文件和目录. 每个 Fi ...

  9. springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3. springboot+shiro+redis(集群re ...

  10. 2 salt-masterless架构

    minion无master的使用用法 需要更改minion配置文件的三个配置项 [root@linux-node2 ~]# vim /etc/salt/minion file_client: loca ...