[NOI2017 D1T1]整数
题目大意:有一个整数 $x$ ,一开始为 $0$ 。有 $n$ 个操作,有两种类型:
$1 \;a\; b$:将 $x$ 加上整数 $a\cdot 2^b$ ,其中 $a$ 为一个整数, $b$ 为一个非负整数
$2\; k$ :询问 $x$ 在用二进制表示时,第 $2^k$ 位的值($0$或$1$)
保证在任何时候, $x\geq 0$ 。
题解:压位线段树,每一个节点压$30$位,考虑到有加减操作,而对于加操作,只是把这一位前的第一个$0$变成$1$,把其间的$1$变成$0$,减相反。所以我们可以在线段树中存一下区间$AND$和区间$OR$,找到某一位前的第一个$1$或第一个$0$,线段树修改一下就行了
卡点:线段树中的$update$和$pushdown$中把$rc$写成了$rt$($QAQ$)
C++ Code:
#include <cstdio>
#include <cstring>
#define base 30
#define maxn 1000010
using namespace std;
const int inf = (1 << base) - 1;
int n, op;
struct ST {
int And[maxn << 2], Or[maxn << 2], V[maxn << 2], tg[maxn << 2];
void init() {
memset(tg, -1, sizeof tg);
}
void pushdown(int rt) {
int lc = rt << 1, rc = rt << 1 | 1, &tmp = tg[rt];
And[lc] = Or[lc] = tg[lc] = tmp;
And[rc] = Or[rc] = tg[rc] = tmp;
tmp = -1;
}
void update(int rt) {
int lc = rt << 1, rc = rt << 1 | 1;
And[rt] = And[lc] & And[rc];
Or[rt] = Or[lc] | Or[rc];
}
void add(int rt, int l, int r, int p, int num) {
if (l > r) return ;
if (l == r) {
Or[rt] = And[rt] = num;
return ;
}
int mid = l + r >> 1;
if (~tg[rt]) pushdown(rt);
if (p <= mid) add(rt << 1, l, mid, p, num);
else add(rt << 1 | 1, mid + 1, r, p, num);
update(rt);
}
void add(int rt, int l, int r, int L, int R, int num) {
if (l > r || L > R) return ;
if (L <= l && R >= r) {
Or[rt] = And[rt] = tg[rt] = num;
return ;
}
int mid = l + r >> 1;
if (~tg[rt]) pushdown(rt);
if (L <= mid) add(rt << 1, l, mid, L, R, num);
if (R > mid) add(rt << 1 | 1, mid + 1, r, L, R, num);
update(rt);
}
int ask(int rt, int l, int r, int p) {
if (l > r) return 0;
if (l == r) return And[rt];
int mid = l + r >> 1, ans;
if (~tg[rt]) pushdown(rt);
if (p <= mid) ans = ask(rt << 1, l, mid, p);
else ans = ask(rt << 1 | 1, mid + 1, r, p);
return ans;
}
int find_1(int rt, int l, int r, int p) {
if (Or[rt] == 0) return -1;
if (l == r) return l;
int mid = l + r >> 1;
if (~tg[rt]) pushdown(rt);
if (p <= mid) {
int tmp = find_1(rt << 1, l, mid, p);
return ~tmp ? tmp : find_1(rt << 1 | 1, mid + 1, r, p);
} else return find_1(rt << 1 | 1, mid + 1, r, p);
}
int find_0(int rt, int l, int r, int p) {
if (And[rt] == inf) return -1;
if (l == r) return l;
int mid = l + r >> 1;
if (~tg[rt]) pushdown(rt);
if (p <= mid) {
int tmp = find_0(rt << 1, l, mid, p);
return ~tmp ? tmp : find_0(rt << 1 | 1, mid + 1, r, p);
} else return find_0(rt << 1 | 1, mid + 1, r, p);
}
} T;
void inc(int p, int num) {
if (!num) return ;
int tmp = T.ask(1, 0, maxn, p) + num;
if (tmp <= inf) T.add(1, 0, maxn, p, tmp);
else {
T.add(1, 0, maxn, p, tmp & inf);
int pos = T.find_0(1, 0, maxn, p + 1);
T.add(1, 0, maxn, p + 1, pos - 1, 0);
inc(pos, 1);
}
}
void dec(int p, int num) {
if (!num) return ;
int tmp = T.ask(1, 0, maxn, p) - num;
if (tmp >= 0) T.add(1, 0, maxn, p, tmp);
else {
T.add(1, 0, maxn, p, tmp + inf + 1);
int pos = T.find_1(1, 0, maxn, p + 1);
T.add(1, 0, maxn, p + 1, pos - 1, inf);
dec(pos, 1);
}
}
void modify(int a, int b) {
int blo = b / base, num = b % base;
if (a > 0) {
inc(blo, (a << num) & inf);
a = a >> base - num;
if (a) inc(blo + 1, a);
} else {
a = -a;
dec(blo, (a << num) & inf);
a = a >> base - num;
if (a) dec(blo + 1, a);
}
}
int query(int k) {
int tmp = T.ask(1, 0, maxn, k / base);
return (tmp & (1 << k % base)) && 1;
}
int main() {
// freopen("integer.in", "r", stdin);
// freopen("integer.out" ,"w", stdout);
scanf("%d%*d%*d%*d", &n);
T.init();
while (n--) {
scanf("%d", &op);
if (op --> 1) {
int k;
scanf("%d", &k);
// printf("%d\n", k);
printf("%d\n", query(k));
// puts("query");
} else {
int a, b;
scanf("%d%d", &a, &b);
if (!a) continue;
modify(a, b);
// puts("modify");
}
}
return 0;
}
[NOI2017 D1T1]整数的更多相关文章
- 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\)实际上对其他位 ...
 - BZOJ4942【noi2017】整数
		
题目背景 在人类智慧的山巅,有着一台字长为10485761048576 位(此数字与解题无关)的超级计算机,著名理论计算机科 学家P博士正用它进行各种研究.不幸的是,这天台风切断了电力系统,超级计算机 ...
 - UOJ #314. 【NOI2017】整数 | 线段树 压位
		
题目链接 UOJ 134 题解 可爱的电音之王松松松出的题--好妙啊. 首先想一个朴素的做法! 把当前的整数的二进制当作01序列用线段树维护一下(序列的第i位就是整数中位权为\(2^k\)的那一位). ...
 - noi2017 T1  整数 ——线段树
		
loj.ac上有 题目传送门 不过我还是把题目搬过来吧 整数(integer)[题目背景]在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科 学家 P 博士正用它进行 ...
 - LOJ2302 「NOI2017」整数
		
「NOI2017」整数 题目背景 在人类智慧的山巅,有着一台字长为$1048576$位(此数字与解题无关)的超级计算机,著名理论计算机科 学家P博士正用它进行各种研究.不幸的是,这天台风切断了电力系统 ...
 - UOJ#314. 【NOI2017】整数 其他
		
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ314.html 题解 如果只加不减,那么瞎势能分析一波可以知道暴力模拟的复杂度是对的. 但是有减法怎么办? ...
 - LOJ#2302. 「NOI2017」整数
		
$n \leq 1000000$个操作:一,给$x$加上$a*2^b$:二,问$x$的某个二进制位$k$.$b,k \leq 30n$,$|a| \leq 1e9$. 30暴露了一切..可以把30个二 ...
 - 【noi2017】 整数  线段树or模拟
		
ORZYYB 题目大意:你需要维护一个有$3\times 10^7$个二进制位的数,有一种修改方式和一种询问方式 对这个数加上$a\times2^b$,其中$|a|≤10^9$,$b≤3\times ...
 
随机推荐
- css公共类
			
/*iOS弹性滚动*/ .scrolling{ position: absolute; width: 100%; height:100%; overflow-x:hidden; overflow-y: ...
 - weex踩坑记录
			
weex框架样式问题--我暂时使用最基本的样式css,weex前端开发的话web端会显示各种的html标签.写出的样式也都会显示的很好,但是在app端的话,就没有很好的兼容性,只是支持文档中的一些标签 ...
 - 使用CSS3制作首页登录界面实例
			
响应式设计 在这个页面中,使用下面3点来完成响应式设计 1.最大宽度 .设定了一个 max-width 的最大宽度,以便在大屏幕时兼容.: 2.margin : 30px auto; 使其保持时刻居中 ...
 - VSCode插件整理
			
VSCode插件整理 VSCode插件整理 官网地址 vscode常用配置(User Settings文件) 基本插件 前端插件 VUE部分 python MarkDown部分 连接Linux 本地与 ...
 - labview在编写程序框图中遇到的一些布尔按钮控制布尔指示灯问题
			
上图布尔控件按下,数据0x04成功发送给下位机,布尔灯不亮. ............... ............. ........... 下图布尔控件按下, ...
 - Python爬虫爬取百度翻译之数据提取方法json
			
工具:Python 3.6.5.PyCharm开发工具.Windows 10 操作系统 说明:本例为实现输入中文翻译为英文的小程序,适合Python爬虫的初学者一起学习,感兴趣的可以做英文翻译为中文的 ...
 - C语言实例解析精粹学习笔记——43(希尔排序)
			
实例说明: 用希尔排序方法对数组进行排序.由于书中更关注的实例,对于原理来说有一定的解释,但是对于第一次接触的人来说可能略微有些简略.自己在草稿纸上画了好久,后来发现网上有好多很漂亮的原理图. 下面将 ...
 - HyperLedger Fabric 1.4 架构(6.2)
			
6.2.1 架构演进 Fabric架构经历了0.6版本到1.0版本的演进,架构上进行了重大改进,从0.6版本的结构简单演进到可扩展.多通道的设计,在架构上有了质的飞跃:从1.0版本以后,架 ...
 - Android面试收集录 2D绘图与动画技术
			
1.如何在Android应用程序的窗口上绘制图形? 继承View 实现View中的onDraw()方法 2.如何绘制圆,空心椭圆? canvas.drawArc或canvas.drawCircle方法 ...
 - Android面试收集录 对话框、信息提示和菜单
			
1.如何使用AlertDialog显示一个列表? 使用AlertDialog.Builder.setItems方法. 在setItems中定义DialogInterface.OnClickListen ...