题目

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

1.查询k在区间内的排名

2.查询区间内排名为k的值

3.修改某一位值上的数值

4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)

5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作

第二行有n个数,表示有序序列

下面有m行,opt表示操作标号

若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名

若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数

若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k

若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱

若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

题解

树套树模板题。

对于每一个线段树上的节点,我们都在上面建一个平衡树。

对于操作1,我们把一个长度为len的区间分解为\(\lfloor log_2(len) \rfloor\)个子区间,分别处理,把每个区间的排名加起来就好了。

对于操作2,我们二分答案,对于二分出来的一个答案执行操作1,check以下即可。

对于操作3,我们删除再插入。

对于操作4和操作5,我们把每个区间(前驱/后继)的(最大值/最小值)搞一搞就好啦。

PS.谁能告诉我bzoj上那些2000ms的是怎么做的。。。

代码

  1. #include <algorithm>
  2. #include <cctype>
  3. #include <cstdio>
  4. using namespace std;
  5. const int maxn = 4e6 + 5;
  6. const int inf = 1e9;
  7. int ans, n, m, opt, l, r, k, pos, sz, Max;
  8. int a[maxn], fa[maxn], ch[maxn][2], size[maxn], cnt[maxn], data[maxn], rt[maxn];
  9. inline int read() {
  10. int x = 0, f = 1;
  11. char ch = getchar();
  12. while (!isdigit(ch)) {
  13. if (ch == '-')
  14. f = -1;
  15. ch = getchar();
  16. }
  17. while (isdigit(ch)) {
  18. x = x * 10 + ch - '0';
  19. ch = getchar();
  20. }
  21. return x * f;
  22. }
  23. struct Splay {
  24. void clear(int x) {
  25. fa[x] = ch[x][0] = ch[x][1] = size[x] = cnt[x] = data[x] = 0;
  26. }
  27. void update(int x) {
  28. if (x) {
  29. size[x] = cnt[x];
  30. if (ch[x][0])
  31. size[x] += size[ch[x][0]];
  32. if (ch[x][1])
  33. size[x] += size[ch[x][1]];
  34. }
  35. }
  36. void zig(int x) {
  37. int y = fa[x], z = fa[y], l = (ch[y][1] == x), r = l ^ 1;
  38. fa[ch[y][l] = ch[x][r]] = y;
  39. fa[ch[x][r] = y] = x;
  40. fa[x] = z;
  41. if (z)
  42. ch[z][ch[z][1] == y] = x;
  43. update(y);
  44. update(x);
  45. }
  46. void splay(int i, int x, int aim = 0) {
  47. for (int y; (y = fa[x]) != aim; zig(x))
  48. if (fa[y] != aim)
  49. zig((ch[fa[y]][0] == y) == (ch[y][0] == x) ? y : x);
  50. if (aim == 0)
  51. rt[i] = x;
  52. }
  53. void insert(int i, int v) {
  54. int x = rt[i], y = 0;
  55. if (x == 0) {
  56. rt[i] = x = ++sz;
  57. fa[x] = ch[x][0] = ch[x][1] = 0;
  58. size[x] = cnt[x] = 1;
  59. data[x] = v;
  60. return;
  61. }
  62. while (1) {
  63. if (data[x] == v) {
  64. cnt[x]++;
  65. update(y);
  66. splay(i, x);
  67. return;
  68. }
  69. y = x;
  70. x = ch[x][v > data[x]];
  71. if (x == 0) {
  72. ++sz;
  73. fa[sz] = y;
  74. ch[sz][0] = ch[sz][1] = 0;
  75. size[sz] = cnt[sz] = 1;
  76. data[sz] = v;
  77. ch[y][v > data[y]] = sz;
  78. update(y);
  79. splay(i, sz);
  80. rt[i] = sz;
  81. return;
  82. }
  83. }
  84. }
  85. void find(int i, int v) {
  86. int x = rt[i];
  87. while (1) {
  88. if (data[x] == v) {
  89. splay(i, x);
  90. return;
  91. } else
  92. x = ch[x][v > data[x]];
  93. }
  94. }
  95. int pre(int i) {
  96. int x = ch[rt[i]][0];
  97. while (ch[x][1])
  98. x = ch[x][1];
  99. return x;
  100. }
  101. int succ(int i) {
  102. int x = ch[rt[i]][1];
  103. while (ch[x][0])
  104. x = ch[x][0];
  105. return x;
  106. }
  107. void del(int i) {
  108. int x = rt[i];
  109. if (cnt[x] > 1) {
  110. cnt[x]--;
  111. return;
  112. }
  113. if (!ch[x][0] && !ch[x][1]) {
  114. clear(rt[i]);
  115. rt[i] = 0;
  116. return;
  117. }
  118. if (!ch[x][0]) {
  119. int oldroot = x;
  120. rt[i] = ch[x][1];
  121. fa[rt[i]] = 0;
  122. clear(oldroot);
  123. return;
  124. }
  125. if (!ch[x][1]) {
  126. int oldroot = x;
  127. rt[i] = ch[x][0];
  128. fa[rt[i]] = 0;
  129. clear(oldroot);
  130. return;
  131. }
  132. int y = pre(i), oldroot = x;
  133. splay(i, y);
  134. rt[i] = y;
  135. ch[rt[i]][1] = ch[oldroot][1];
  136. fa[ch[oldroot][1]] = rt[i];
  137. clear(oldroot);
  138. update(rt[i]);
  139. return;
  140. }
  141. int rank(int i, int v) {
  142. int x = rt[i], ans = 0;
  143. while (1) {
  144. if (!x)
  145. return ans;
  146. if (data[x] == v)
  147. return ((ch[x][0]) ? size[ch[x][0]] : 0) + ans;
  148. else if (data[x] < v) {
  149. ans += ((ch[x][0]) ? size[ch[x][0]] : 0) + cnt[x];
  150. x = ch[x][1];
  151. } else if (data[x] > v) {
  152. x = ch[x][0];
  153. }
  154. }
  155. }
  156. int find_pre(int i, int v) {
  157. int x = rt[i];
  158. while (x) {
  159. if (data[x] < v) {
  160. if (ans < data[x])
  161. ans = data[x];
  162. x = ch[x][1];
  163. } else
  164. x = ch[x][0];
  165. }
  166. return ans;
  167. }
  168. int find_succ(int i, int v) {
  169. int x = rt[i];
  170. while (x) {
  171. if (v < data[x]) {
  172. if (ans > data[x])
  173. ans = data[x];
  174. x = ch[x][0];
  175. } else
  176. x = ch[x][1];
  177. }
  178. return ans;
  179. }
  180. } sp;
  181. void insert(int k, int l, int r, int x, int v) {
  182. int mid = (l + r) >> 1;
  183. sp.insert(k, v);
  184. if (l == r)
  185. return;
  186. if (x <= mid)
  187. insert(k << 1, l, mid, x, v);
  188. else
  189. insert(k << 1 | 1, mid + 1, r, x, v);
  190. }
  191. void askrank(int k, int l, int r, int x, int y, int val) {
  192. int mid = (l + r) >> 1;
  193. if (x <= l && r <= y) {
  194. ans += sp.rank(k, val);
  195. return;
  196. }
  197. if (x <= mid)
  198. askrank(k << 1, l, mid, x, y, val);
  199. if (mid + 1 <= y)
  200. askrank(k << 1 | 1, mid + 1, r, x, y, val);
  201. }
  202. void change(int k, int l, int r, int pos, int val) {
  203. int mid = (l + r) >> 1;
  204. sp.find(k, a[pos]);
  205. sp.del(k);
  206. sp.insert(k, val);
  207. if (l == r)
  208. return;
  209. if (pos <= mid)
  210. change(k << 1, l, mid, pos, val);
  211. else
  212. change(k << 1 | 1, mid + 1, r, pos, val);
  213. }
  214. void askpre(int k, int l, int r, int x, int y, int val) {
  215. int mid = (l + r) >> 1;
  216. if (x <= l && r <= y) {
  217. ans = max(ans, sp.find_pre(k, val));
  218. return;
  219. }
  220. if (x <= mid)
  221. askpre(k << 1, l, mid, x, y, val);
  222. if (mid + 1 <= y)
  223. askpre(k << 1 | 1, mid + 1, r, x, y, val);
  224. }
  225. void asksucc(int k, int l, int r, int x, int y, int val) {
  226. int mid = (l + r) >> 1;
  227. if (x <= l && r <= y) {
  228. ans = min(ans, sp.find_succ(k, val));
  229. return;
  230. }
  231. if (x <= mid)
  232. asksucc(k << 1, l, mid, x, y, val);
  233. if (mid + 1 <= y)
  234. asksucc(k << 1 | 1, mid + 1, r, x, y, val);
  235. }
  236. int main() {
  237. #ifdef D
  238. freopen("input", "r", stdin);
  239. #endif
  240. n = read(), m = read();
  241. for (int i = 1; i <= n; i++)
  242. a[i] = read(), Max = max(Max, a[i]), insert(1, 1, n, i, a[i]);
  243. for (int i = 1; i <= m; i++) {
  244. opt = read();
  245. if (opt == 1) {
  246. l = read(), r = read(), k = read();
  247. ans = 0;
  248. askrank(1, 1, n, l, r, k);
  249. printf("%d\n", ans + 1);
  250. } else if (opt == 2) {
  251. l = read(), r = read(), k = read();
  252. int head = 0, tail = Max + 1;
  253. while (head != tail) {
  254. int mid = (head + tail) >> 1;
  255. ans = 0;
  256. askrank(1, 1, n, l, r, mid);
  257. if (ans < k)
  258. head = mid + 1;
  259. else
  260. tail = mid;
  261. }
  262. printf("%d\n", head - 1);
  263. } else if (opt == 3) {
  264. pos = read();
  265. k = read();
  266. change(1, 1, n, pos, k);
  267. a[pos] = k;
  268. Max = std::max(Max, k);
  269. } else if (opt == 4) {
  270. l = read();
  271. r = read();
  272. k = read();
  273. ans = 0;
  274. askpre(1, 1, n, l, r, k);
  275. printf("%d\n", ans);
  276. } else if (opt == 5) {
  277. l = read();
  278. r = read();
  279. k = read();
  280. ans = inf;
  281. asksucc(1, 1, n, l, r, k);
  282. printf("%d\n", ans);
  283. }
  284. }
  285. }

[bzoj3196]Tyvj 1730 二逼平衡树——线段树套平衡树的更多相关文章

  1. bzoj3196: Tyvj 1730 二逼平衡树 树套树

    地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3196 题目: 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec ...

  2. BZOJ3196二逼平衡树——线段树套平衡树(treap)

    此为平衡树系列最后一道:二逼平衡树您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询 ...

  3. 【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

    线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/p ...

  4. BZOJ3196: Tyvj 1730 二逼平衡树

    传送门 主席树的常数蜜汁优越,在BZOJ上跑了rnk1. 做法很简单,主席树套BIT. 1-3做法很简单,第四个和第五个做法转换成前两个就行了. //BZOJ 3196 //by Cydiater / ...

  5. 【分块】bzoj3196 Tyvj 1730 二逼平衡树

    分块 或 树套树. 在每个块中维护一个有序表,查询时各种二分,全都是分块的经典操作,就不详细说了. 块的大小定为sqrt(n*log2(n))比较快. #include<cstdio> # ...

  6. bzoj3196 二逼平衡树——线段树套平衡树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 人生中第一棵树套树! 写了一个晚上,成功卡时 9000ms+ 过了! 很要注意数组的大 ...

  7. bzoj 3196二逼平衡树 线段树套平衡树

    比较裸的树套树,对于区间K值bz上有一道裸题,详见题解http://www.cnblogs.com/BLADEVIL/p/3455336.html(其实题解也不是很详细) //By BLADEVIL ...

  8. [bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

    Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在 ...

  9. 【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

    这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然 ...

随机推荐

  1. My数据库和Ms数据库的区别

    mssql 是微软的那个 SQL Server,运行于windows2000,2003等平台 mysql 是由瑞典mySQL AB 公司开发,目前属于Oracle旗下公司.可运行在windows平台. ...

  2. Python3基础 lambda表达式 简单示例

    镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...

  3. linux Cron 执行Django 任务计划

    用shell 脚本调用python 脚本如下 #!/bin/bash export FLAVOR=liveexport PYTHONPATH=$PYTHONPATH:/home/alex/Django ...

  4. jQuery 获取和设置type为hidden的input的值

    HTML代码 <input type="hidden" name="type" id="type" value="1&quo ...

  5. 部署statspack工具(二)之解决方案1

    7.解决方案一:调整buffer cache sys@TESTDB12>alter system set sga_max_size=804m scope=spfile;        //重启数 ...

  6. KingbaseES的HA搭建

    1.配置资源前准备: 安装好数据库并保持两台机器用户ID及组ID一致,组ID和用户ID在/etc/passwd查看,如不保持一致,可能导致切机时阵列的属主改变,导致数据库无法启动. 建议用法,现在两台 ...

  7. JS之ONLoad事件

    如果我问你window.load和window.onload分别是什么意思,恐怕你会回答我:“这不是页面加载完就执行吗”. 但是答案是不一定,得看你怎么用.看一下例子吧 例1: <!DOCTYP ...

  8. SVG六基本元素

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. redis内存占用说明

    执行info命令后,找到Memory这一栏,就可以看到内存的使用信息了,如下图: # Memory used_memory:13490096 //数据占用了多少内存(字节) used_memory_h ...

  10. 我的Linux软件集

    把我常用的软件记下来,以后重装安装的时候方便一些- 这个博文会不断更新的- 开发工具类 Monodevelop 编写C#控制台程序和GTK#窗口程序,很好,虽然没有VS强大,但是够用了 CodeBlo ...