LOJ 2302 「NOI2017」整数——压位线段树
题目:https://loj.ac/problem/2302
压30位,a最多落在两个位置上,拆成两次操作。
该位置加了 a 之后,如果要进位或者借位,查询一下连续一段 0 / 1 ,修改掉,再在含有 1 / 0 的那个位置上 -1 或者 +1 。
注意是在那个位置上 -1 或者 +1 而不是 -lowbit 或者 +lowbit 。
询问都是 <=30n ,所以只维护 30n 的范围即可。注意线段树压 30 位,开 n 个位置恰好是 0*n ~ 29*n,所以开 n+1 个位置。
线段树只需维护自己区间是全 0 / 1 还是都有。找连续一段 0/1 就在线段树上二分即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
const int N=2e6+,bs=;
int n,nr,tot,Ls[N],Rs[N],lx[N],vl[N],tg[N];
int bin[bs+],U; bool fx;
void build(int l,int r,int cr)
{
tg[cr]=-; lx[cr]=vl[cr]=;
if(l==r)return; int mid=l+r>>;
ls=++tot; build(l,mid,ls);
rs=++tot; build(mid+,r,rs);
}
void pshd(int cr)
{
if(tg[cr]==-)return; int k=tg[cr]; tg[cr]=-;
tg[ls]=tg[rs]=k;
if(k==){ vl[ls]=vl[rs]=U; lx[ls]=lx[rs]=;}
else { vl[ls]=vl[rs]=; lx[ls]=lx[rs]=;}
}
void pshp(int cr)
{
if((!lx[ls])&&(!lx[rs]))lx[cr]=;
else if(lx[ls]==&&lx[rs]==)lx[cr]=; else lx[cr]=;
}
void updt(int cr)
{ if(!vl[cr])lx[cr]=; else if(vl[cr]==U)lx[cr]=; else lx[cr]=;}
int fnd(int l,int r,int cr,int L,int R,int k)
{
if(l>=L&&r<=R)
{
if(lx[cr]==(!k))return nr+; if(l==r)return l;
int mid=l+r>>; pshd(cr);
if(lx[ls]!=(!k))return fnd(l,mid,ls,L,R,k);
return fnd(mid+,r,rs,L,R,k);
}
int mid=l+r>>,d=nr+; pshd(cr);
if(L<=mid)d=fnd(l,mid,ls,L,R,k);
if(d==nr+)d=fnd(mid+,r,rs,L,R,k);
return d;
}
void mdfy(int l,int r,int cr,int L,int R,int k)
{
if(l>=L&&r<=R)
{
tg[cr]=k; if(k==){vl[cr]=U;lx[cr]=;}
else {vl[cr]=;lx[cr]=;} return;
}
int mid=l+r>>; pshd(cr);
if(L<=mid)mdfy(l,mid,ls,L,R,k);
if(mid<R)mdfy(mid+,r,rs,L,R,k);
pshp(cr);
}
void mdfy2(int l,int r,int cr,int p,int k)
{
if(l==r)
{
if(k==)vl[cr]++; else vl[cr]--;/////
/*if(k==1){ int tmp=(vl[cr]^U); vl[cr]+=(tmp&(-tmp));}
else vl[cr]-=(vl[cr]&(-vl[cr]));*/
updt(cr); return;
}
int mid=l+r>>; pshd(cr);
if(p<=mid)mdfy2(l,mid,ls,p,k);
else mdfy2(mid+,r,rs,p,k);
pshp(cr);
}
void add(int p)
{
int d=fnd(,nr,,p,nr,);//fnd first 0
if(p<d)mdfy(,nr,,p,d-,);
if(d<=nr)mdfy2(,nr,,d,);//chg 0 to 1
}
void dec(int p)
{
int d=fnd(,nr,,p,nr,);
if(p<d)mdfy(,nr,,p,d-,);
if(d<=nr)mdfy2(,nr,,d,);
}
void solve(int l,int r,int cr,int p,int k)
{
if(l==r)
{
if(!fx)vl[cr]+=k; else vl[cr]-=k;
if(vl[cr]>=bin[bs]){ vl[cr]-=bin[bs];add(l+);}
if(vl[cr]<){ vl[cr]+=bin[bs];dec(l+);}
updt(cr); return;
}
int mid=l+r>>; pshd(cr);
if(p<=mid)solve(l,mid,ls,p,k); else solve(mid+,r,rs,p,k);
pshp(cr);
}
bool qry(int l,int r,int cr,int p,int p2)
{
if(l==r)return vl[cr]&bin[p2];
int mid=l+r>>; pshd(cr);
if(p<=mid)return qry(l,mid,ls,p,p2);
else return qry(mid+,r,rs,p,p2);
}
int main()
{
n=rdn(); nr=n+; int tp=rdn();tp=rdn();tp=rdn();
bin[]=;for(int i=;i<=bs;i++)bin[i]=bin[i-]<<;
U=bin[bs]-; tot=;build(,nr,);
for(int i=,op,a,b,l,r;i<=n;i++)
{
op=rdn();
if(op==)
{
a=rdn();b=rdn(); l=b; r=b+bs-;
l=l/bs+; r=r/bs+;
if(a<)a=-a,fx=; else fx=;
if(l<r)
{
int k=a&(bin[l*bs-b]-);
a>>=(l*bs-b); k<<=(b-(l-)*bs);
solve(,nr,,l,k); solve(,nr,,r,a);
}
else solve(,nr,,l,a);
}
else
{
a=rdn(); l=a/bs+; a-=(l-)*bs;
printf("%d\n",qry(,nr,,l,a));
}
}
return ;
}
LOJ 2302 「NOI2017」整数——压位线段树的更多相关文章
- LOJ#2302. 「NOI2017」整数
$n \leq 1000000$个操作:一,给$x$加上$a*2^b$:二,问$x$的某个二进制位$k$.$b,k \leq 30n$,$|a| \leq 1e9$. 30暴露了一切..可以把30个二 ...
- 【bzoj4942】[Noi2017]整数 压位+线段树
题目描述 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 $x$ ,一开始为0. 接下来有 $n$ 个操作,每个操作都是以下两种类型中的一种: 1 a b :将 $x$ 加上整数 ...
- BZOJ 4942 NOI2017 整数 (压位+线段树)
题目大意:让你维护一个数x(x位数<=3*1e7),要支持加/减a*2^b,以及查询x的第i位在二进制下是0还是1 作为一道noi的题,非常考验写代码综合能力,敲+调+借鉴神犇的代码 3个多小时 ...
- loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)
题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...
- 【NOI】2017 整数(BZOJ 4942,LOJ2302) 压位+线段树
[题目]#2302. 「NOI2017」整数 [题意]有一个整数x,一开始为0.n次操作,加上a*2^b,或询问2^k位是0或1.\(n \leq 10^6,|a| \leq 10^9,0 \leq ...
- 【LOJ】#3109. 「TJOI2019」甲苯先生的线段树
LOJ#3109. 「TJOI2019」甲苯先生的线段树 发现如果枚举路径两边的长度的话,如果根节点的值是$x$,左边走了$l$,右边走了$r$ 肯定答案会是$(2^{l + 1} + 2^{r + ...
- LibreOJ2302 - 「NOI2017」整数
Portal Description 有一个整数\(x=0\),对其进行\(n(n\leq10^6)\)次操作: 给出\(a(|a|\leq10^9),b(b\leq30n)\),将\(x\)加上\( ...
- 「NOI2017」整数 解题报告
「NOI2017」整数 有一些比较简单的\(\log^2n\)做法 比如暴力在动态开点线段树上维护每个位置为\(0\)还是\(1\),我们发现涉及到某一位加上\(1\)或者减去\(1\)实际上对其他位 ...
- loj #2305. 「NOI2017」游戏
#2305. 「NOI2017」游戏 题目描述 小 L 计划进行 nnn 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏. 小 L 的赛车有三辆,分别用大写字母 AAA.BBB. ...
随机推荐
- maven 依赖调解
项目A有两条依赖关系 A->B->C->X(1.0),A->D->X(2.0) ,X是A的传递性依赖,但是两条路径上有两个版本的依赖,会选择哪个呢? maven 依赖调 ...
- python简单的函数定义和用法实例
python简单的函数定义和用法实例 这篇文章主要介绍了python简单的函数定义和用法,实例分析了Python自定义函数及其使用方法,具有一定参考借鉴价值,需要的朋友可以参考下 具体分析如下: 这里 ...
- Vue Cli 3:创建项目
一 简介 Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,有几个独立的部分. 1 CLI (@vue/cli) 是一个全局安装的 npm 包,提供了终端里的 vue 命令.(vue ...
- Altium Designer chapter6总结
绘制PCB中需要注意的如下: (1)网络表的载入:网络表是原理图与PCB之间的桥梁,而AD实现了真正的双向同步设计.在装入网表之前需要先添加相应的封装库. (2)元件的布局:一般采用手工布局:按照模块 ...
- python实现自动发送邮件
Python发送邮件成功的前提,应是先开启授权码.目前使用广泛的邮箱有:163邮箱.qq邮箱等. 163邮箱开启授权码的方法如下图: qq邮箱开启授权码的方法如下图: 接下来代码的实现: import ...
- 06 案例篇:系统的 CPU 使用率很高,但为啥却找不到高 CPU 的应用?
上一节我讲了 CPU 使用率是什么,并通过一个案例教你使用 top.vmstat.pidstat 等工具,排查高 CPU 使用率的进程,然后再使用 perf top 工具,定位应用内部函数的问题.不过 ...
- SEC5 - MySQL 查询语句--------------进阶1:基础查询
# 进阶1:基础查询 /* 语法: select 查询列表 from 表名: 特点: 1.查询列表可以是:表中的字段.常量值.表达式.表达式.函数 2.查询的结果是一个虚拟的表格 如何执行:执行谁,请 ...
- Pikachu漏洞练习平台实验——不安全的文件下载和上传(七)
1.不安全的文件下载 1.1.概述 文件下载功能在很多web系统上都会出现,一般我们当点击下载链接,便会向后台发送一个下载请求,一般这个请求会包含一个需要下载的文件名称,后台在收到请求后 会开始执行下 ...
- python学习那点事---pycharm使用弹框问题如何解决
学习python的目标:年后可以找一份不错的维护工作. 2019.11.4日是第一天开始学习python,从开始安装python3.6版本和pycharm开始.安装python版本非常顺利的就完成了, ...
- 利用Lua实现二叉查找树并进行各种遍历
-- author : coder_zhang-- date : 2014-6-25 root = nil function insert_node(number) if root == nil th ...