[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 ...
随机推荐
- ERROR: bootstrap checks failed
错误描述:Linux默认配置的参数过小,需要自己设置 max file descriptors [4096] for elasticsearch process is too low, increas ...
- JavaSE基础复习---Class类与反射机制
---恢复内容开始--- 目录: 1.java.lang.class类 2.Java中的反射机制 3.运行时与编译时概念 1. java.lang.class类 Java程序在运行时,Java运行时系 ...
- Sqoop帮助文档
1.列出MySql数据库中的所有数据库 $ sqoop list-databases --connect jdbc:mysql://192.168.254.105:3306/--username ro ...
- c# string.format和tostring()
字符 说明 示例 输出 C 货币 string.Format("{0:C3}", 2) $2.000 D 十进制 string.Format("{0:D3}", ...
- Python的入坑之路(1)
(故事背景:由于涉及到机密的原因,暂时不方便透露,待后期再写.) 国庆长假过完之后,回来上班第二天下午,Boss跟龙哥把我叫了出去,问我要不要转人工智能.一脸懵逼的我,带着一脸懵逼听Boss说人工智能 ...
- 3 python3 编码解码问题 upd接受数据
1.python3下的中文乱码:send_data.encode("utf-8") from socket import * udp_socket = socket(AF_INET ...
- 深度学习之卷积神经网络CNN
转自:https://blog.csdn.net/cxmscb/article/details/71023576 一.CNN的引入 在人工的全连接神经网络中,每相邻两层之间的每个神经元之间都是有边相连 ...
- loj2587 「APIO2018」铁人两项
圆方树orz,参见猫的课件(apio和wc的)以及这里那里 #include <iostream> #include <cstdio> using namespace std; ...
- 【数据结构】 Queue 的简单实现
[数据结构] Queue 的简单实现 public class XQueue<T> { /// <summary> /// 第一个元素 /// </summary> ...
- Qt irrlicht(鬼火)3D引擎 摄像机旋转问题
点击打开链接Irrlicht中的摄像有一个函数 setUpVector() if (m_device != 0 ) { core::vector3df rotation(y,x,0.f); m_cam ...