题意:

一开始有n个非负整数h[i],接下来会进行m次操作,第i次会给出一个数c[i],要求选出c[i]个大于0的数并将它们-1,问最多可以进行多少次?

分析:

首先一个显然的贪心就是每次都将最大的c[i]个数-1,于是就可以用无旋式treap来维护,基本操作中split_k和split_v都使用普通的merge,但在提取区间并打完标记后,因为整个序列的单调性发生改变,需要使用启发式合并(只在修改过后使用)。

code

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<string>
  6. #include<algorithm>
  7. #include<cmath>
  8. #include<vector>
  9. #include<ctime>
  10. #include<queue>
  11. using namespace std;
  12. template<typename T>
  13. inline void read(T &x) {
  14. T i = 0, f = 1;
  15. char ch = getchar();
  16. for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
  17. if(ch == '-') f = -1, ch = getchar();
  18. for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
  19. x = i * f;
  20. }
  21. template<typename T>
  22. inline void wr(T x) {
  23. if(x < 0) putchar('-'), x = -x;
  24. if(x > 9) wr(x / 10);
  25. putchar(x % 10 + '0');
  26. }
  27. const int N = 1e6 + 50, OO = 0x3f3f3f3f;
  28. int n, m, h[N], c[N];
  29. inline int Rand(){
  30. static int RAND_VAL = 1388593021;
  31. return RAND_VAL += RAND_VAL << 2 | 1;
  32. }
  33. #define SZ(x) (x?x->sze:0)
  34. #define V(x) (x?x->val:OO)
  35. struct node{
  36. node *lc, *rc;
  37. int sze, pri, val, tag;
  38. node():lc(NULL), rc(NULL){}
  39. inline void add(int v){
  40. val += v, tag += v;
  41. }
  42. inline void pushDown(){
  43. if(tag != 0){
  44. if(lc) lc->add(tag);
  45. if(rc) rc->add(tag);
  46. tag = 0;
  47. }
  48. }
  49. inline node* upt(){
  50. sze = SZ(lc) + SZ(rc) + 1;
  51. return this;
  52. }
  53. inline void print(){
  54. pushDown();
  55. if(lc) lc->print();
  56. cout<< val<<" ";
  57. if(rc) rc->print();
  58. }
  59. }pool[N], *tail = pool, *rt = NULL;
  60. inline node* newNode(int v){
  61. node *x = tail++;
  62. x->val = v;
  63. x->lc = x->rc = NULL;
  64. x->pri = Rand();
  65. x->tag = 0;
  66. x->sze = 1;
  67. return x;
  68. }
  69. inline node* Merge_o(node *x, node *y){
  70. if(!x) return y;
  71. if(!y) return x;
  72. node *L, *R;
  73. if(x->pri < y->pri){
  74. x->pushDown();
  75. x->rc = Merge_o(x->rc, y);
  76. return x->upt();
  77. }
  78. else {
  79. y->pushDown();
  80. y->lc = Merge_o(x, y->lc);
  81. return y->upt();
  82. }
  83. }
  84. inline void Split_v(node *x, int v, node *&L, node *&R);
  85. inline node* Merge(node *x, node *y){
  86. if(!x) return y;
  87. if(!y) return x;
  88. x->pushDown(), y->pushDown();
  89. if(x->pri > y->pri) swap(x, y);
  90. node *L, *R;
  91. Split_v(y, x->val, L, R);
  92. x->lc = Merge(x->lc, L);
  93. x->rc = Merge(x->rc, R);
  94. x->upt();
  95. return x;
  96. }
  97. inline void Split_k(node *x, int k, node *&L, node *&R){
  98. if(x == NULL){L = NULL, R = NULL; return;}
  99. x->pushDown();
  100. if(SZ(x->lc) < k){
  101. Split_k(x->rc, k - SZ(x->lc) - 1, L, R);
  102. x->rc = NULL; x->upt();
  103. L = Merge_o(x, L);
  104. }
  105. else{
  106. Split_k(x->lc, k, L, R);
  107. x->lc = NULL; x->upt();
  108. R = Merge_o(R, x);
  109. }
  110. }
  111. inline void Split_v(node *x, int v, node *&L, node *&R){
  112. if(x == NULL){L = NULL, R = NULL; return;}
  113. x->pushDown();
  114. if(V(x) <= v){
  115. Split_v(x->rc, v, L, R);
  116. x->rc = NULL; x->upt();
  117. L = Merge_o(x, L);
  118. }
  119. else{
  120. Split_v(x->lc, v, L, R);
  121. x->lc = NULL, x->upt();
  122. R = Merge_o(R, x);
  123. }
  124. }
  125. inline node* build(){
  126. static node* stk[N];
  127. node* pre;
  128. int top = 0;
  129. for(register int i = 1; i <= n; i++){
  130. node *x = newNode(h[i]);
  131. pre = NULL;
  132. while(top && stk[top]->pri > x->pri)
  133. pre = stk[top]->upt(), stk[top--] = NULL;
  134. if(stk[top]) stk[top]->rc = x;
  135. x->lc = pre; stk[++top] = x;
  136. }
  137. while(top) stk[top--]->upt();
  138. return stk[1];
  139. }
  140. int main(){
  141. freopen("h.in", "r", stdin);
  142. read(n), read(m);
  143. for(register int i = 1; i <= n; i++) read(h[i]);
  144. for(register int i = 1; i <= m; i++) read(c[i]);
  145. sort(h + 1, h + n + 1);
  146. rt = build();
  147. for(register int i = 1; i <= m; i++){
  148. if(!c[i]) continue;
  149. if(c[i] > n){
  150. wr(i - 1);
  151. return 0;
  152. }
  153. node *L, *R, *p, *q;
  154. Split_v(rt, 0, L, R);
  155. if(SZ(R) >= c[i]){
  156. Split_k(R, SZ(R) - c[i], p, q);
  157. if(q) q->add(-1);
  158. R = Merge(p, q);
  159. }
  160. else{
  161. wr(i - 1);
  162. return 0;
  163. }
  164. rt = Merge(L, R);
  165. }
  166. wr(m);
  167. return 0;
  168. }

NOIP 模拟 序列操作 - 无旋treap的更多相关文章

  1. 【算法学习】Fhq-Treap(无旋Treap)

    Treap——大名鼎鼎的随机二叉查找树,以优异的性能和简单的实现在OIer们中广泛流传. 这篇blog介绍一种不需要旋转操作来维护的Treap,即无旋Treap,也称Fhq-Treap. 它的巧妙之处 ...

  2. 【序列操作V】平衡树(无旋treap)

    题目描述 维护一个队列,初始为空.依次加入 n(1≤n≤105)个数 ai(-109≤ai≤109),第 i(1≤i≤n)个数加入到当前序列第 bi(0≤bi≤当前序列长度)个数后面.输出最终队列. ...

  3. 无旋treap的区间操作实现

    最近真的不爽...一道维修数列就做了我1上午+下午1h+1晚上+晚上1h+上午2h... 一道不错的自虐题... 由于这一片主要讲思想,代码我放这里了 不会无旋treap的童鞋可以进这里 呵呵... ...

  4. [转载]无旋treap:从单点到区间(例题 BZOJ1500&NOI2005 维护数列 )

    转自ZZH大佬,原文:http://www.cnblogs.com/LadyLex/p/7182631.html 1500: [NOI2005]维修数列 Time Limit: 10 Sec  Mem ...

  5. [BZOJ3223]文艺平衡树 无旋Treap

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个 ...

  6. [您有新的未分配科技点] 无旋treap:从单点到区间(例题 BZOJ1500&NOI2005 维护数列 )

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MB Description Input 输入的第1 行包含两个数N 和M(M ≤20 ...

  7. 无旋treap大法好

    无旋Treap大法好 原理? 是一棵二叉查找树: 一个节点左子树权值都比他小,右子树权值都比他大 所以可以维护序列(以位置为权值),或数值(以数值为权值) 是一个堆: 每个节点除了上述提到的权值外,还 ...

  8. 模板 - 数据结构 - 可持久化无旋Treap/PersistentFHQTreap

    有可能当树中有键值相同的节点时,貌似是要对Split和Merge均进行复制的,本人实测:只在Split的时候复制得到了一个WA,但只在Merge的时候复制还是AC,可能是恰好又躲过去了.有人说假如确保 ...

  9. BZOJ3678 wangxz与OJ (平衡树 无旋treap)

    题面 维护一个序列,支持以下操作: 1.在某个位置插入一段值连续的数. 2.删除在当前序列位置连续的一段数. 3.查询某个位置的数是多少. 题解 显然平衡树,一个点维护一段值连续的数,如果插入或者删除 ...

随机推荐

  1. dot 语法全介绍

    0. 保存 保存为 pdf:dot -Tpdf iris.dot -o iris.pdf 1. 基本 (1)无向图.有向图.子图 graph G {} // 无向图 digraph G {} // 有 ...

  2. Vue 自定义全局消息框组件

    消息弹框组件,默认3秒后自动关闭,可设置info/success/warning/error类型 效果图: 文件目录: Message.vue <template> <transit ...

  3. 6. MongoDB

    https://www.mongodb.com/ https://pan.baidu.com/s/1mhPejwO#list/path=%2F 安装MongoDB# 安装MongoDB http:// ...

  4. oracle里long类型的总结

    转自原文oracle中long类型为什么不推荐使用 不是不推荐使用的,是一般用不到,而有些时候是会用到的,所以不能一概而论.1.LONG 数据类型中存储的是可变长字符串,最大长度限制是2GB.2.对于 ...

  5. Codeforces 232A - Cycles (构造 + 思维)

    题目链接: 232A - Cycles(点击打开) 题意: 要构成一个存在 \(k\) 个三元环的图,需要多少个点,输出顶点数 \(n\),并输出图. 题解: 题目中的任何图都可以用 \(90\)~ ...

  6. python 字符串大小写转换(不能使用swapcase()方法)

    python 3字符串大小写转换 要求不能使用swapcase()方法 #!/usr/bin/env python # -*- coding:utf-8 -*- # Author:Hiuhung Wa ...

  7. AspJpeg2.0组件教程完整版 aspjpeg教程...

    AspJpeg是一款功能强大的基于Microsoft IIS环境的图片处理组件,网络上对其进行详细和深入介绍的中文文章并不多,即使有一般也只是牵涉到图片缩略图和图片水印,这与其为英文版本有着密切的关系 ...

  8. Oracle中暂时表空间的清理

    作者:iamlaosong Oracle暂时表空间主要用来做查询和存放一些缓冲区数据. 暂时表空间消耗的主要原因是须要对查询的中间结果进行排序.暂时表空间的主要作用: 索引create或rebuild ...

  9. html练习(3)

    1.这个小练习用到了css的四种选择器id选择器,类选择器,html选择器,通配符选择器. (1)假设一个元素中用到了各种选择器,而且选择器中的属性发生了冲突,则 优先级为id选择器>类选择器& ...

  10. 自旋锁spinlock解析

    1 基础概念 自旋锁与相互排斥锁有点类似,仅仅是自旋锁不会引起调用者睡眠.假设自旋锁已经被别的运行单元保持.调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁."自旋"一词就 ...