题目链接

UOJ 134

题解

可爱的电音之王松松松出的题……好妙啊。

首先想一个朴素的做法!

把当前的整数的二进制当作01序列用线段树维护一下(序列的第i位就是整数中位权为\(2^k\)的那一位)。

如何做加法?一下子加一个整数比较麻烦,可以把整数拆成一个个二进制位,一位位地加1。如果当前要加一的位置就是0,直接加就好了;否则显然要进位,松松松出的题肯定肯定不能暴力进位骗分(=v=)……所以线段树维护区间是否全是1,每次加的时候找右边(即更高位)第一个为0的位置,然后把那个位置修改为1,b和那个位置中间所有的位置都改成0就好了。

像这样(为了看着不反人类,最低位在右边,最高位在左边):

  1. 001111111
  2. 10
  3. ---------
  4. 010000001

减法怎么做呢?如果这一位就是1则直接减,否则找右边第一个为1的位置,然后单点修改为0,区间修改为1即可。

  1. 110000001
  2. 10
  3. ---------
  4. 101111111

但是这样做还是会T的!

于是要压位!

把30(或60?)个位用一个数存起来,然后类似上面的这样做。注意这时候不要还把a一位位拆开加了,最多只用拆成两部分(为了契合线段树中压位后每一“位”的大小)然后分别加就好了……

代码:

  1. #include <cstdio>
  2. #include <cmath>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <queue>
  6. #define space putchar(' ')
  7. #define enter putchar('\n')
  8. using namespace std;
  9. typedef long long ll;
  10. template <class T>
  11. void read(T &x){
  12. char c;
  13. bool op = 0;
  14. while(c = getchar(), c < '0' || c > '9')
  15. if(c == '-') op = 1;
  16. x = c - '0';
  17. while(c = getchar(), c >= '0' && c <= '9')
  18. x = x * 10 + c - '0';
  19. if(op) x = -x;
  20. }
  21. template <class T>
  22. void write(T x){
  23. if(x < 0) putchar('-'), x = -x;
  24. if(x >= 10) write(x / 10);
  25. putchar(x % 10 + '0');
  26. }
  27. const int N = 500005, S = 60;
  28. const ll INF = (1LL << S) - 1;
  29. int n, m, t, pos[4*N];
  30. ll data[N], tag[4*N];
  31. bool all[4*N][2];
  32. void single_change(int k, ll x){
  33. if(pos[k] != -1) data[pos[k]] = x;
  34. if(x == 0) all[k][0] = 1, all[k][1] = 0, tag[k] = 0;
  35. else if(x == INF) all[k][0] = 0, all[k][1] = 1, tag[k] = INF;
  36. else all[k][0] = all[k][1] = 0, tag[k] = -1;
  37. }
  38. void pushdown(int k){
  39. if(tag[k] == -1) return;
  40. single_change(k << 1, tag[k]);
  41. single_change(k << 1 | 1, tag[k]);
  42. tag[k] = -1;
  43. }
  44. void pushup(int k){
  45. all[k][0] = all[k << 1][0] & all[k << 1 | 1][0];
  46. all[k][1] = all[k << 1][1] & all[k << 1 | 1][1];
  47. }
  48. void build(int k, int l, int r){
  49. all[k][0] = 1, tag[k] = pos[k] = -1;
  50. if(l == r) return (void)(pos[k] = l);
  51. int mid = (l + r) >> 1;
  52. build(k << 1, l, mid);
  53. build(k << 1 | 1, mid + 1, r);
  54. }
  55. void range_change(int k, int l, int r, int ql, int qr, ll x){
  56. if(ql <= l && qr >= r) return single_change(k, x);
  57. pushdown(k);
  58. int mid = (l + r) >> 1;
  59. if(ql <= mid) range_change(k << 1, l, mid, ql, qr, x);
  60. if(qr > mid) range_change(k << 1 | 1, mid + 1, r, ql, qr, x);
  61. pushup(k);
  62. }
  63. int find_nxt(int k, int l, int r, int p, int o){
  64. if(all[k][!o]) return -1;
  65. if(l == r) return l;
  66. pushdown(k);
  67. int mid = (l + r) >> 1, tmp;
  68. if(p <= mid && (tmp = find_nxt(k << 1, l, mid, p, o)) != -1) return tmp;
  69. return find_nxt(k << 1 | 1, mid + 1, r, p, o);
  70. }
  71. ll query(int k, int l, int r, int p){
  72. if(l == r) return data[l];
  73. pushdown(k);
  74. int mid = (l + r) >> 1;
  75. if(p <= mid) return query(k << 1, l, mid, p);
  76. else return query(k << 1 | 1, mid + 1, r, p);
  77. }
  78. void add(int p, ll x){
  79. ll tmp = query(1, 0, n, p);
  80. range_change(1, 0, n, p, p, (tmp + x) & INF);
  81. if(tmp + x > INF){
  82. int tar = find_nxt(1, 0, n, p + 1, 0);
  83. range_change(1, 0, n, tar, tar, data[tar] + 1);
  84. if(p + 1 <= tar - 1) range_change(1, 0, n, p + 1, tar - 1, 0);
  85. }
  86. }
  87. void sub(int p, ll x){
  88. ll tmp = query(1, 0, n, p);
  89. range_change(1, 0, n, p, p, (tmp - x) & INF);
  90. if(tmp - x < 0){
  91. int tar = find_nxt(1, 0, n, p + 1, 1);
  92. range_change(1, 0, n, tar, tar, data[tar] - 1);
  93. if(p + 1 <= tar - 1) range_change(1, 0, n, p + 1, tar - 1, INF);
  94. }
  95. }
  96. int main(){
  97. read(n), m = n, n = n / 2 + 2;
  98. read(t), read(t), read(t);
  99. build(1, 0, n);
  100. ll op, a, b;
  101. while(m--){
  102. read(op), read(a);
  103. if(op == 1){
  104. read(b);
  105. if(a > 0){
  106. int p = b / S, rst = b % S;
  107. ll x = a << rst & INF;
  108. if(x) add(p, x);
  109. p++, a >>= (S - rst);
  110. if(b) add(p, a);
  111. }
  112. else{
  113. a = -a;
  114. int p = b / S, rst = b % S;
  115. ll x = a << rst & INF;
  116. if(x) sub(p, x);
  117. p++, a >>= (S - rst);
  118. if(b) sub(p, a);
  119. }
  120. }
  121. else write(query(1, 0, n, a / S) >> (a % S) & 1), enter;
  122. }
  123. return 0;
  124. }

UOJ #314. 【NOI2017】整数 | 线段树 压位的更多相关文章

  1. [BZOJ4942][Noi2017]整数 线段树+压位

    用线段树来模拟加减法过程,维护连续一段中是否全为0/1. 因为数字很大,我们60位压一位来处理. #include<iostream> #include<cstring> #i ...

  2. 【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

    [BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依 ...

  3. 2018.10.30 bzoj4942: [Noi2017]整数(线段树压位)

    传送门 直接把修改的数拆成logloglog个二进制位一个一个修改是会TLETLETLE的. 因此我们把303030个二进制位压成一位储存在线段树里面. 然后维护区间中最靠左二进制位不为0/1的下标. ...

  4. 【洛谷3822】[NOI2017] 整数(线段树压位)

    题目: 洛谷 3822 分析: 直接按题意模拟,完了. 将每次加 / 减拆成不超过 \(32\) 个对单独一位的加 / 减. 考虑给一个二进制位(下称「当前位」)加 \(1\) 时,如果这一位本来就是 ...

  5. noi2017 T1 整数 ——线段树

    loj.ac上有  题目传送门 不过我还是把题目搬过来吧 整数(integer)[题目背景]在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科 学家 P 博士正用它进行 ...

  6. 【noi2017】 整数 线段树or模拟

    ORZYYB 题目大意:你需要维护一个有$3\times 10^7$个二进制位的数,有一种修改方式和一种询问方式 对这个数加上$a\times2^b$,其中$|a|≤10^9$,$b≤3\times ...

  7. BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流

    题目链接: [Noi2017]蔬菜 题目大意:有$n$种蔬菜,每种蔬菜有$c_{i}$个,每种蔬菜每天有$x_{i}$个单位会坏掉(准确来说每天每种蔬菜坏掉的量是$x_{i}-$当天这种蔬菜卖出量), ...

  8. POJ-2777-CountColor(线段树,位运算)

    链接:https://vjudge.net/problem/POJ-2777#author=0 题意: Chosen Problem Solving and Program design as an ...

  9. UOJ 217 奇怪的线段树

    http://uoj.ac/problem/217 题意就不X了,思路在这: 居然一开始把sap里面的mn设置为inf了,我是傻逼.. #include<cstdio> #include& ...

随机推荐

  1. 搭建Zookeepeer源码工程

    一.搭建ant环境 1.下载ant&将ant解压至安装目录 http://ant.apache.org/bindownload.cgi 2.配置环境变量 ANT_HOME:配置ant的安装目录 ...

  2. 使用IE浏览提示:该页面无法显示

    问题描述: 我们有一个外部招聘的网站,DBA反馈新版上线过后首页集成的登录部分页面无法打开,一直显示“该页面无法显示”! 问题排查: 1.因为我本身也不是负责这一块的业务,刚开始以为是网站本身程序的问 ...

  3. 【SDOI2017】数字表格

    题面 题解 这道题目还有一种比较有意思的解法. 定义一种运算\((\mathbf f\oplus\mathbf g)(x) = \prod\limits_{d\mid x}\mathbf f(d)^{ ...

  4. JDK8漫谈——集合更强大

    解决什么问题 集合计算不足 解决重复代码 背后思想 管道 封装 数据处理 内容说明 是什么 计算担当.集合用于数据存储,流用于数据计算,不会修改原始数据 内置循环.高级迭代器,内置循环和计算 单向.数 ...

  5. 【亲测有效】Centos安装完成docker后启动docker报错docker: unrecognized service的两种解决方案

    今天在学习Docker的时候 使用yum install docker安装完后启动不了,报错如下: [root@Sakura ~]# service docker start docker: unre ...

  6. Html5计算MD5值

    教程: http://www.tuicool.com/articles/InEBNz 组件: https://github.com/satazor/js-spark-md5

  7. 作用域&作用域链和with,catch语句&闭包

    作用域(函数) 作用域:变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期; 在一些类C编程语言中花括号内的每一段代码都有各自的作用域,而且变量在声明它们的代码段外是不可见的,称之为块 ...

  8. Individual Project-word frequency

    预计时间: 项目要求理解:半小时 c#语言了解:6小时 构思程序框架:2小时 编写调试程序:4小时 项目实际完成时间: 项目要求理解:半小时 c#语言了解:6小时 构思程序框架:2小时 编写调试程序: ...

  9. 【ML】Two-Stream Convolutional Networks for Action Recognition in Videos

    Two-Stream Convolutional Networks for Action Recognition in Videos & Towards Good Practices for ...

  10. iOS GCD中级篇 - dispatch_semaphore(信号量)的理解及使用

    理解这个概念之前,先抛出一个问题 问题描述: 假设现在系统有两个空闲资源可以被利用,但同一时间却有三个线程要进行访问,这种情况下,该如何处理呢? 或者 我们要下载很多图片,并发异步进行,每个下载都会开 ...