[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 ...
随机推荐
- web前端总结面试问题(理论)
一个页面从输入url到页面显示加载完成,这个过程发生了什么? 1.浏览器根据请求的URL交给DNS域名解析,找到真实的IP,向服务器发起请求. 2.服务器交给后台处理完成后返回数据,浏览器接收文件(h ...
- redis之cluster(集群)
搭建redis cluster 1. 准备节点 2. 节点间的通信 3. 分配槽位给节点 redis-cluster架构 多个服务端,负责读写,彼此通信,redis指定了16384个槽. 多匹马儿,负 ...
- 记6种php 加密解密方法
<?php function encryptDecrypt($key, $string, $decrypt){ if($decrypt){ $decrypted = rtrim(mcrypt_d ...
- Python接受流式输入
随笔记录——Python接受终端入若干行输入 Python接受终端的若干行输入时,比较常用的input()不再好用. 1. 导入sys模块: import sys 2. for循环接受输入: for ...
- django之单表查询
一.创建表 1.创建模型: 创建名为book的app,在book下的models.py中创建模型: from django.db import models # Create your models ...
- 牛客网暑期ACM多校训练营(第四场) F
参考:http://www.cnblogs.com/Jadon97/p/9383027.html #include <iostream> #include <cstdio> # ...
- PRO*C 函数事例 1 -- 数据库连接、事务处理
1.程序结构 每一个Pro*C程序都包括两部分:(1)应用程序首部:(2)应用程序体 应用程序首部定义了ORACLE数据库的有关变量, 为在C语言中操纵ORACLE数据库做 ...
- java通过句柄访问对象
在Java里,任何东西都可看作对象.尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“句柄”(Handle),有的人将其称作一个“引用”,甚至一个“指针”. 主类型的数据成员可直接初始化, ...
- VectorDrawable在Android中的配置
一.让Android支持VectorDrawable apply plugin: 'com.android.application' android { defaultConfig { vectorD ...
- win10子系统Ubuntu18.04下安装图形界面
前提:windows 10 已经安装WSL(windows subsystem for linux),并能正确运行Bash. 要想使用Linux的图形用户界面通常有两种方法,一种是使用X-Window ...