noi2017 T1 整数 ——线段树
loj.ac上有 题目传送门
不过我还是把题目搬过来吧
整数(integer)
【题目背景】
在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科 学家 P 博士正用它进行各种研究。不幸的是,这天台风切断了电力系统,超级计算机 无法工作,而 P 博士明天就要交实验结果了,只好求助于学过 OI 的你......
【题目描述】 P 博士将他的计算任务抽象为对一个整数的操作。
具体来说,有一个整数 x ,一开始为 0。 接下来有 n 个操作,每个操作都是以下两种类型中的一种:
• 1 a b :将 x 加上整数 a·2b,其中 a 为一个整数,b 为一个非负整数
• 2 k :询问 x 在用二进制表示时,位权为 2k 的位的值(即这一位上的 1 代表 2k )
保证在任何时候,x≥0。
【输入格式】 从标准输入读入数据。
输入的第一行包含四个正整数 n,t1,t2,t3,n 的含义见题目描述,t1,t2,t3 的具体含义 见子任务。
接下来 n 行,每行给出一个操作,具体格式和含义见题目描述。
同一行输入的相邻两个元素之间,用恰好一个空格隔开。
【输出格式】
输出到标准输出。
对于每个询问操作,输出一行,表示该询问的答案(000 或 111)。 对于加法操作,没有任何输出
样例输入 1
10 3 1 2
1 100 0
1 2333 0
1 -233 0
2 5
2 7
2 15
1 5 15
2 15
1 -1 12
2 15
【样例 1 输出】
0
1
0
1
0
【子任务】 在所有测试点中,
1 ≤ t1 ≤ 3,1 ≤ t2 ≤ 4,1 ≤ t3 ≤ 2。
不同的 t1,t2,t3 对应的特殊限制 如下:
• 对于 t1 = 1 的测试点,满足 a = 1
•对于 t1 = 2 的测试点,满足 |a|= 1
• 对于 t1 = 3 的测试点,满足 |a|≤109 • 对于 t2 = 1 的测试点,满足 0≤b,k≤30
• 对于 t2 = 2 的测试点,满足 0≤b,k≤100
• 对于 t2 = 3 的测试点,满足 0≤b,k≤n
• 对于 t2 = 4 的测试点,满足 0≤b,k≤30n
• 对于 t3 = 1 的测试点,保证所有询问操作都在所有修改操作之后
• 对于 t3 = 2 的测试点,不保证询问操作和修改操作的先后顺序
这道题首先 a*2^b 这个东西呢按我的想法是把 a 拆成2的x次幂的和 然后+b
如果只有加法当然很好写 但是这道题 a 可能是负的
所以我开了两个数组 s1 s2 来存 s1 存的是正的 s2 存的是负的
注意存的时候进位 均摊复杂度只有o(1) 所以暴力进位就好了
然后问题就转换成了已知两个高精度数,问他们的差的某一位是什么
然后分类可得
我们记一个数为 1(0)x
1 (0) 表示询问的这一位的值(因为是二进制,所以不是1就是0)
x就是询问位后面那一串东西(一坨1 0 混合体)
考虑减法是否退位的时候呢
1. x>=y:
1x-1y=0(x-y)
1x-0y=1(x-y)
0x-1y=1(x-y)
0x-0y=0(x-y)
2. x<y:
1x-1y=1(x-y+2^k)
1x-0y=0(x-y+2^k)
0x-1y=0(x-y+2^k)
0x-0y=1(x-y+2^k)
举个例子吧
10-10=00
10-00=10
01-10=11
01-01=00
10-11=11
10-01=01
00-11=01
00-01=11
注 题目保证x始终大于等于0 所以s1总和也一定大于s2
这样分析之后呢 问题就转换成了从1-x(即询问位)-1这个区间里s1 s2 的大小关系
如果 s1>=s2
那么答案就是 s1^s2(^念做异或)
如果 s2<=s2
那么答案就是 s1==s2 (==念做同或)
那么 x 和 y 的比较 其实就是比较字典序 找到第一个不一样的地方 哪个是1 哪个就大 (这么很好证明我就不详细讲了) 注意这里讲的都是二进制
算了举个例子吧 如果x是1000 y是0111 那么x是不是一定大于y
所以我们可以采用线段树维护区间内s1 s2 的大小
当然我这里采用的是zkw线段树 (自带底层优化自然会比较快 而且修改也很好写)
毕竟三千万(3e7)个叶子结点 同时线段树中下标也就是二进制中 2的次数
操作自然就是 区间内单点修改,前缀查询
那么我们每次操作1拆完a加上b以及进位之后
我们要记录一波 修改到的最左位置到最右位置 进位自然也算修改
然后就在线段树上暴力修改顺便上传信息 复杂度是 o( r-l + log(n))
操作2 询问的时候我们就找到区间中靠右(也就是比较大的位置)的第一个不一样的地方然后判断一波就好了
到这里题目就完美解决了 修改(modify)以及 查找(find) 就看代码吧
注: find我的写法呢 是向上走时,如果x是右孩子且x的兄弟为1才向下走
实测跑得也蛮快的 23333
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int M=3e7+,N=<<;
int read(){
int ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
int s1[M],s2[M],cnt;
int l,r,a,b,n,k;
void prepare(int x){
if(!x) return ;
int v=x>?x:-x,w[];
cnt=;
for(int i=;i>=;i--){
int now=<<i;
if(now&v) v-=now,w[++cnt]=i;
if(!v) break;
}
l=w[cnt]+b; r=w[]+b;
if(x>)
for(int i=;i<=cnt;i++){
int now=w[i]+b;
while(s1[now]) s1[now++]=,r=max(r,now);
s1[now]=;
}
else
for(int i=;i<=cnt;i++){
int now=w[i]+b;
while(s2[now]) s2[now++]=,r=max(r,now);
s2[now]=;
}
}
int tr[*N],T,now;
void modify(){
for(int i=l;i<=r;i++) tr[i+N]=s1[i]^s2[i];
for(l=(l+N)>>,r=(r+N)>>;l;l>>=,r>>=)
for(int i=l;i<=r;i++) tr[i]=tr[i<<]|tr[i<<^];
}
int find(int k){
for(k+=N;k;k>>=) if(k&&tr[k^]){
for(k^=;k<N;k=k<<^tr[k<<^]);
return k-N;
}
return -;
}
int main()
{
n=read(); T=read(); T=read(); T=read();
for(int i=;i<=n;i++){
k=read();
if(k==){
a=read(); b=read();
prepare(a);
modify();
}
else{
a=read();
now=find(a);
if(s1[now]>s2[now]||now==-) printf("%d\n",s1[a]^s2[a]);
else printf("%d\n",s1[a]==s2[a]);
}
}
return ;
}
noi2017 T1 整数 ——线段树的更多相关文章
- UOJ #314. 【NOI2017】整数 | 线段树 压位
题目链接 UOJ 134 题解 可爱的电音之王松松松出的题--好妙啊. 首先想一个朴素的做法! 把当前的整数的二进制当作01序列用线段树维护一下(序列的第i位就是整数中位权为\(2^k\)的那一位). ...
- 【noi2017】 整数 线段树or模拟
ORZYYB 题目大意:你需要维护一个有$3\times 10^7$个二进制位的数,有一种修改方式和一种询问方式 对这个数加上$a\times2^b$,其中$|a|≤10^9$,$b≤3\times ...
- 【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)
[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依 ...
- [BZOJ4942][Noi2017]整数 线段树+压位
用线段树来模拟加减法过程,维护连续一段中是否全为0/1. 因为数字很大,我们60位压一位来处理. #include<iostream> #include<cstring> #i ...
- 省选模拟赛 4.26 T1 dp 线段树优化dp
LINK:T1 算是一道中档题 考试的时候脑残了 不仅没写优化 连暴力都打挂了. 容易发现一个性质 那就是同一格子不会被两种以上的颜色染.(颜色就三种. 通过这个性质就可以进行dp了.先按照左端点排序 ...
- F. Wi-Fi(线段树实现dp)
题:http://codeforces.com/contest/1216/problem/F dp[i][0]:表示第i个位置不装的最小代价 dp[i][1]:表示第i个位置装的最小代价 T1的线段树 ...
- [Bzoj4942][Noi2017]整数(线段树)
4942: [Noi2017]整数 Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 363 Solved: 237[Submit][Status][D ...
- 【bzoj4942】[Noi2017]整数 压位+线段树
题目描述 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 $x$ ,一开始为0. 接下来有 $n$ 个操作,每个操作都是以下两种类型中的一种: 1 a b :将 $x$ 加上整数 ...
- 【洛谷3822】[NOI2017] 整数(线段树压位)
题目: 洛谷 3822 分析: 直接按题意模拟,完了. 将每次加 / 减拆成不超过 \(32\) 个对单独一位的加 / 减. 考虑给一个二进制位(下称「当前位」)加 \(1\) 时,如果这一位本来就是 ...
随机推荐
- TCL之表达式
- thinkPHP5.0 save和saveAll,新增和更新的问题
今天遇到一个问题,在模型中使用save保存数据之后,使用saveAll继续新增数据,结果报 缺少更新条件,网上搜了下发现一篇文章https://www.jianshu.com/p/1848f61de6 ...
- OLAP和OLTP
OLTP与OLAP的介绍 数据处理分为两种技术架构系统:OLTP与OLAP OLTP(联机事务处理过程) OLTP是传统的关系型数据库的主要应用,主要是基本的,日常的事务处理,例如银行的交易 ...
- C语言进阶—— 逻辑运算符分析15
印象中的逻辑运算符: ---学生:老师,在我的印象中,逻辑运算符用在条件判断的时候,真挺简单的,还有必要深究吗? ---老师:逻辑运算符确实在条件判断的时候用的比较多,但是并不能说简单... 请思考下 ...
- mysql学习第二天函数
-- 1.绝对值 select abs(-1)from dual -- 2.求平方根select sqrt(6)from dual -- 3.圆周率select pi()from dual -- 4. ...
- python基础之继承实现原理、子类调用父类的方法、封装
继承实现原理 python中的类可以同时继承多个父类,继承的顺序有两种:深度优先和广度优先. 一般来讲,经典类在多继承的情况下会按照深度优先的方式查找,新式类会按照广度优先的方式查找 示例解析: 没有 ...
- K-均值聚类——电影类型
K-均值聚类 K-均值算法试图将一系列样本分割成K个不同的类簇(其中K是模型的输入参数),其形式化的目标函数称为类簇内的方差和(within cluster sum of squared errors ...
- 4 Django简介
MVC与MTV模型 MVC Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的.松耦合的方式连接在一起,模型负责业务 ...
- HDU 1384 Intervals(差分约束)
Intervals Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- Web 开发的未来:React、Falcor 和 ES6
Web 开发的未来:React.Falcor 和 ES6 Widen是一家数字资产管理解决方案提供商.目前,其技术栈还非常传统,包括服务器端的Java.浏览器端的AngularJS.提供REST AP ...