NOI 2017 整数(线段树)
题意
思路
拆分成每个二进制位的加减来考虑,维护那个整数的二进制位。不难发现,进位就是找右边第一个 \(0\) 的位置,并将其赋值为 \(1\) ,之间的数全部赋值为 \(0\) ,退位就是找右边第一个 \(1\) 的位置,并将其赋值为 \(0\) ,之间的数全部赋值为 \(1\),这个可以通过在线段树上二分实现。
当然直接搞的话复杂度 \(O(30n\log 30n)\) 当然是过不去的,但是我们一个位置只维护一个二进制数也太不值得了,数据范围中的 \(30n\) 已经在暗示,需要将每 \(30\) 二进制数一起维护。进位退位仍然是一样的找法,有一点细节,具体实现请参考代码。
代码
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
using namespace std;
template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
typedef long long ll;
const int N=1.1e6+5;
const int B=30;
int w[N<<2],tag[N<<2],flg[N<<2];
int n,t1,t2,t3,LB,RB;
inline void Read(int &x)
{
x=0;char ch=getchar();bool f=0;
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
if(f)x=~x+1;
}
void tag_up(int k,int val,int l,int r)
{
tag[k]=val;
flg[k]=val;
if(l==r)w[k]=val*((1<<B)-1);
}
void push_down(int k,int l,int r)
{
if(tag[k]==-1)return;
int mid=(l+r)>>1;
tag_up(k<<1,tag[k],l,mid);
tag_up(k<<1|1,tag[k],mid+1,r);
tag[k]=-1;
}
void push_up(int k)
{
flg[k]=(flg[k<<1]==flg[k<<1|1]?flg[k<<1]:-1);
}
void update(int k,int L,int R,int val,int l=LB,int r=RB)//[L,R] 赋值为val*(2^B)
{
if(L<=l&&r<=R){tag_up(k,val,l,r);return;}
push_down(k,l,r);
int mid=(l+r)>>1;
if(L<=mid)update(k<<1,L,R,val,l,mid);
if(R>mid)update(k<<1|1,L,R,val,mid+1,r);
push_up(k);
}
int modify(int k,int x,int val,int l=LB,int r=RB) //x位置加上val,返回进退位信息
{
if(l==r)
{
w[k]+=val;
int res=0;
if(w[k]>=(1<<B))
{
w[k]-=(1<<B);
res=1;
}
else if(w[k]<0)
{
w[k]+=(1<<B);
res=-1;
}
if(w[k]==0)flg[k]=0;
else if(w[k]==(1<<B)-1)flg[k]=1;
else flg[k]=-1;
return res;
}
push_down(k,l,r);
int mid=(l+r)>>1,res;
if(x<=mid)res=modify(k<<1,x,val,l,mid);
else res=modify(k<<1|1,x,val,mid+1,r);
push_up(k);
return res;
}
int query(int k,int x,int l=LB,int r=RB) //查询x位置的数
{
if(l==r)return w[k];
push_down(k,l,r);
int mid=(l+r)>>1;
if(x<=mid)return query(k<<1,x,l,mid);
else return query(k<<1|1,x,mid+1,r);
}
int deal(int k,int x,bool val,int l=LB,int r=RB) //修改x及x以右第一个二进制位出现val的为!val,并将数二进制位之前的赋为val,返回这个数的位置
{
if(flg[k]==!val)return -1;
if(l==r)
{
if(val)FOR(i,0,B-1)
{
if(w[k]&(1<<i))
{
w[k]^=1<<i;
break;
}else w[k]|=1<<i;
}
else FOR(i,0,B-1)
{
if(~w[k]&(1<<i))
{
w[k]|=1<<i;
break;
}else w[k]^=1<<i;
}
if(w[k]==0)flg[k]=0;
else if(w[k]==(1<<B)-1)flg[k]=1;
else flg[k]=-1;
return l;
}
int mid=(l+r)>>1;
push_down(k,l,r);
if(x>mid)
{
int res=deal(k<<1|1,x,val,mid+1,r);
push_up(k);
return res;
}
else
{
int res=deal(k<<1,x,val,l,mid);
if(res!=-1)
{
push_up(k);
return res;
}
else
{
res=deal(k<<1|1,x,val,mid+1,r);
push_up(k);
return res;
}
}
}
void Update(int val,int pos)
{
int res=modify(1,pos,val);
if(res==1)
{
res=deal(1,pos+1,0);
if(pos+1<=res-1)update(1,pos+1,res-1,0);
}
else if(res==-1)
{
res=deal(1,pos+1,1);
if(pos+1<=res-1)update(1,pos+1,res-1,1);
}
}
int Query(int a){return query(1,a);}
int main()
{
memset(tag,-1,sizeof(tag));
Read(n),Read(t1),Read(t2),Read(t3);
LB=0,RB=n+1000;
update(1,LB,RB,0);
FOR(i,1,n)
{
int op,a,b;
Read(op);
if(op==1)
{
Read(a),Read(b);
int l=b%B,r=B-l;
if(a>0)
{
Update((a&((1<<r)-1))<<l,b/B);
Update(a>>r,b/B+1);
}
else if(a<0)
{
a=-a;
Update(-((a&((1<<r)-1))<<l),b/B);
Update(-(a>>r),b/B+1);
}
}
else
{
Read(a);
printf("%d\n",Query(a/B)>>(a%B)&1);
}
}
return 0;
}
NOI 2017 整数(线段树)的更多相关文章
- [NOI 2017]整数
Description 题库链接 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 \(x\) ,一开始为 \(0\) . 接下来有 \(n\) 个操作,每个操作都是以下两种类型中 ...
- UOJ #314. 【NOI2017】整数 | 线段树 压位
题目链接 UOJ 134 题解 可爱的电音之王松松松出的题--好妙啊. 首先想一个朴素的做法! 把当前的整数的二进制当作01序列用线段树维护一下(序列的第i位就是整数中位权为\(2^k\)的那一位). ...
- noi2017 T1 整数 ——线段树
loj.ac上有 题目传送门 不过我还是把题目搬过来吧 整数(integer)[题目背景]在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科 学家 P 博士正用它进行 ...
- 【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)
[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依 ...
- [BZOJ4942][Noi2017]整数 线段树+压位
用线段树来模拟加减法过程,维护连续一段中是否全为0/1. 因为数字很大,我们60位压一位来处理. #include<iostream> #include<cstring> #i ...
- 洛谷 P3960 [ NOIP 2017 ] 列队 —— 线段树
题目:https://www.luogu.org/problemnew/show/P3960 NOIP 题,不用很复杂的数据结构...但又参考了许多: 要求支持维护删除第 k 个和在末尾插入的数据结构 ...
- noi.ac #38 线段树+时间复杂度分析
\(des\) 存在参数数组 \(a\),\(a\) 升序排列 \[a_1 < a_2 < \cdots < a_m, m <= 10\] 存在长度为 \(n\) 价值数组 \ ...
- 【noi2017】 整数 线段树or模拟
ORZYYB 题目大意:你需要维护一个有$3\times 10^7$个二进制位的数,有一种修改方式和一种询问方式 对这个数加上$a\times2^b$,其中$|a|≤10^9$,$b≤3\times ...
- 【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 ...
随机推荐
- Linux 的基本操作(系统的远程登录)
系统的远程登录 首先要说一下,该部分内容对于linux初学者来讲并不是特别重要的,可以先跳过该章节,先学下一章,等学完后再回来看这一章. Linux大多应用于服务器,而服务器不可能像PC一样放在办公室 ...
- Vue.js——60分钟快速入门(转载)
Vue.js介绍 Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的API,使得我们 ...
- 七牛 OCR 接口调试 & 七牛鉴权 Token 应用
接口规约 PHP 实现 核心代码 执行结果 源代码 Java 实现 核心代码 执行结果 源代码 [现学现卖]图片内容审核接口 Python 实现 核心代码 执行结果 源代码 Go 实现 核心代码 执行 ...
- mac sed 使用踩坑实录
[转自别处] 比如我sed想做文件原地的替换,但是怎么写都出错,错误提示还莫名其妙,后来多方搜索才知道Mac上的sed如果参数有-i就必须加上备份指令,即-i后添加任意字符,那些字符就作为备份文件的后 ...
- php 获取IP地址 并获取坐标lat lng 并获取到所在地区
函数方法:ps:只能放在服务器上起效果,放在本地是无法起效果的 /* **根据ip获取坐标 ***/ function get_zuobiao(){ $user_IP = ($_SERVER[&quo ...
- juqery 给本身的class加上一个class 或也可以实现关注商品,取消关注商品
$("#goods1").on("click",".ICON-fen-LOVE",function(){ var $this = $(thi ...
- UML关系实现、泛化,依赖、组合
图片via<大话设计模式> UML一目了然
- Excel GET.DOCUMENT说明
GET.DOCUMENT(type_num, name_text) Type_num 指明信息类型的数.下表列出 type_num 的可能值与对应结果. Type_num 返回 1 ...
- 常用邮箱的 IMAP/POP3/SMTP 设置
通过网上查找的资料和自己的总结完成了下面的文章,看完之后相信大家对这三种协议会有更深入的理解.如有错误的地方望指正. POP3 POP3是Post Office Protocol 3的简称,即邮局协议 ...
- nginx入门与实战 安装 启动 配置nginx Nginx状态信息(status)配置 正向代理 反向代理 nginx语法之location详解
nginx入门与实战 网站服务 想必我们大多数人都是通过访问网站而开始接触互联网的吧.我们平时访问的网站服务 就是 Web 网络服务,一般是指允许用户通过浏览器访问到互联网中各种资源的服务. Web ...