题面

传送门

思路

发现强制在线了......

本来可以树套树解决的问题,现在外层不能使用线段树了,拿什么替代呢?

我们需要一种支持单点插入、下套数据结构、数据结构上传合并复杂度最多单log,不能旋转的数据结构

这不是摆明了用重量平衡树吗?

我选了替罪羊树作为上层结构,下面套了一棵线段树,就做完了

查询的时候把替罪羊树上对应的log个区间提取出来,一起在底层权值线段树上二分即可

详见代码注释

Code

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cassert>
  6. #include<queue>
  7. using namespace std;
  8. inline int read(){
  9. int re=0,flag=1;char ch=getchar();
  10. while(!isdigit(ch)){
  11. if(ch=='-') flag=-1;
  12. ch=getchar();
  13. }
  14. while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
  15. return re*flag;
  16. }
  17. int s[20000010],ls=0,rs=0;
  18. namespace ctrl{//内存分配器
  19. int cnt=0;
  20. int get(){
  21. int re;
  22. if(ls^rs){
  23. re=s[ls];
  24. ls++;if(ls==20000000) ls=0;
  25. }
  26. else re=(++cnt);
  27. return re;
  28. }
  29. void rec(int x){
  30. s[rs++]=x;
  31. if(rs==20000000) rs=0;
  32. }
  33. }
  34. vector<int>st;
  35. namespace seg{
  36. int ch[20000010][2],sum[20000010];
  37. void insert(int &cur,int l,int r,int pos,int val){//权值线段树修改
  38. if(!cur){
  39. cur=ctrl::get();
  40. ch[cur][0]=ch[cur][1]=0;
  41. }
  42. if(l==r){sum[cur]+=val;return;}
  43. int mid=(l+r)>>1;
  44. if(mid>=pos) insert(ch[cur][0],l,mid,pos,val);
  45. else insert(ch[cur][1],mid+1,r,pos,val);
  46. sum[cur]=sum[ch[cur][0]]+sum[ch[cur][1]];
  47. }
  48. vector<int>s,ss;
  49. int query(int l,int r,int k){
  50. if(l==r) return l;
  51. int mid=(l+r)>>1,re=0,i;
  52. for(i=0;i<s.size();i++){//多个对象同步查询,s是对应区间,ss是对应单点
  53. re+=sum[ch[s[i]][0]];
  54. }
  55. for(i=0;i<ss.size();i++){
  56. re+=(ss[i]>=l&&ss[i]<=mid);
  57. }
  58. if(re>=k){
  59. for(i=0;i<s.size();i++) s[i]=ch[s[i]][0];
  60. return query(l,mid,k);
  61. }
  62. else{
  63. for(i=0;i<s.size();i++) s[i]=ch[s[i]][1];
  64. return query(mid+1,r,k-re);
  65. }
  66. }
  67. void dump(int cur){//拍扁替罪羊的过程中回收线段树节点
  68. if(!cur) return;
  69. dump(ch[cur][0]);dump(ch[cur][1]);
  70. ch[cur][0]=ch[cur][1]=sum[cur]=0;ctrl::rec(cur);
  71. }
  72. }
  73. int root,unb;
  74. double alpha=0.8;
  75. namespace scp{//替罪羊
  76. int ch[150010][2],siz[150010],rt[150010],v[150010],cnt;
  77. void update(int cur){
  78. siz[cur]=siz[ch[cur][0]]+siz[ch[cur][1]]+1;
  79. }
  80. void dfs(int u){//拍扁
  81. if(!u) return;
  82. seg::dump(rt[u]);
  83. dfs(ch[u][0]);
  84. st.push_back(u);
  85. dfs(ch[u][1]);
  86. }
  87. void build(int l,int r,int &cur){
  88. if(l>r) return;
  89. int mid=(l+r)>>1;
  90. cur=st[mid];
  91. ch[cur][0]=ch[cur][1]=0;siz[cur]=1;rt[cur]=0;
  92. build(l,mid-1,ch[cur][0]);build(mid+1,r,ch[cur][1]);
  93. update(cur);
  94. for(int i=l;i<=r;i++)
  95. seg::insert(rt[cur],0,70000,v[st[i]],1);
  96. }
  97. void rebuild(int &cur){//替罪羊重构
  98. st.clear();dfs(cur);
  99. build(0,st.size()-1,cur);
  100. }
  101. void insert(int &cur,int rk,int val){//替罪羊插入、判断重构
  102. if(!cur){
  103. cur=++cnt;
  104. ch[cur][0]=ch[cur][1]=0;siz[cur]=1;v[cur]=val;rt[cur]=0;
  105. seg::insert(rt[cur],0,70000,val,1);return;
  106. }
  107. seg::insert(rt[cur],0,70000,val,1);
  108. int L=siz[ch[cur][0]];
  109. if(L>=rk) insert(ch[cur][0],rk,val);
  110. else insert(ch[cur][1],rk-L-1,val);
  111. update(cur);
  112. if((double)(siz[cur])*alpha>(double)(max(siz[ch[cur][0]],siz[ch[cur][1]]))){
  113. if(unb){
  114. if(ch[cur][0]==unb) rebuild(ch[cur][0]);
  115. else rebuild(ch[cur][1]);
  116. unb=0;
  117. }
  118. }
  119. else unb=cur;
  120. }
  121. int ori;
  122. void change(int cur,int rk,int val){//替罪羊区间修改
  123. seg::insert(rt[cur],0,70000,val,1);
  124. if(siz[ch[cur][0]]+1==rk){ori=v[cur];v[cur]=val;}
  125. else if(siz[ch[cur][0]]>=rk) change(ch[cur][0],rk,val);
  126. else change(ch[cur][1],rk-siz[ch[cur][0]]-1,val);
  127. seg::insert(rt[cur],0,70000,ori,-1);
  128. }
  129. void query(int cur,int l,int r){//替罪羊上提取查询区间,如果区间覆盖了当前点,就把当前点加入查询序列
  130. assert(cur);
  131. if(l==1&&r==siz[cur]){
  132. seg::s.push_back(rt[cur]);return;
  133. }
  134. if(siz[ch[cur][0]]+1>=l&&siz[ch[cur][0]]+1<=r) seg::ss.push_back(v[cur]);
  135. if(r<=siz[ch[cur][0]]) query(ch[cur][0],l,r);
  136. else if(l>siz[ch[cur][0]]+1) query(ch[cur][1],l-siz[ch[cur][0]]-1,r-siz[ch[cur][0]]-1);
  137. else{
  138. if(l<=siz[ch[cur][0]]) query(ch[cur][0],l,siz[ch[cur][0]]);
  139. if(r>siz[ch[cur][0]]+1) query(ch[cur][1],1,r-siz[ch[cur][0]]-1);
  140. }
  141. }
  142. }
  143. int n,Q;
  144. int main(){
  145. n=read();int i,t1,t2,t3;char ss[10];int lastans=0;
  146. for(i=1;i<=n;i++){
  147. t1=read();
  148. scp::insert(root,i,t1);
  149. if(unb){
  150. unb=0;
  151. scp::rebuild(root);
  152. }
  153. }
  154. Q=read();
  155. while(Q--){
  156. scanf("%s",ss);
  157. if(ss[0]=='Q'){
  158. t1=read();t2=read();t3=read();
  159. t1^=lastans;t2^=lastans;t3^=lastans;
  160. seg::s.clear();seg::ss.clear();
  161. scp::query(root,t1,t2);
  162. printf("%d\n",lastans=seg::query(0,70000,t3));
  163. }
  164. if(ss[0]=='M'){
  165. t1=read();t2=read();
  166. t1^=lastans;t2^=lastans;
  167. scp::change(root,t1,t2);
  168. }
  169. if(ss[0]=='I'){
  170. t1=read();t2=read();unb=0;
  171. t1^=lastans;t2^=lastans;
  172. scp::insert(root,t1-1,t2);
  173. if(unb){
  174. unb=0;
  175. scp::rebuild(root);
  176. }
  177. }
  178. }
  179. }

[bzoj3065] 带插入区间第k小值 [重量平衡树套线段树]的更多相关文章

  1. 「BZOJ3065」带插入区间第K小值 替罪羊树×线段树

    题目描述 从前有\(n\)只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力\(a_i\).跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间\(k\)小值.他 ...

  2. BZOJ 3065 带插入区间第K小值

    题目描述 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值. ...

  3. 【XSY2720】区间第k小 整体二分 可持久化线段树

    题目描述 给你你个序列,每次求区间第\(k\)小的数. 本题中,如果一个数在询问区间中出现了超过\(w\)次,那么就把这个数视为\(n\). 强制在线. \(n\leq 100000,a_i<n ...

  4. [BZOJ3065]带插入区间K小值 解题报告 替罪羊树+值域线段树

    刚了一天的题终于切掉了,数据结构题的代码真**难调,这是我做过的第一道树套树题,做完后感觉对树套树都有阴影了......下面写一下做题记录. Portal Gun:[BZOJ3065]带插入区间k小值 ...

  5. 【学习笔记】浅析平衡树套线段树 & 带插入区间K小值

    常见的树套树 一般来说,在嵌套数据结构中,线段树多被作为外层结构使用. 但线段树毕竟是 静态 的结构,导致了一些不便. 下面是一个难以维护的例子: 带插入区间 \(k\) 小值问题 来源:Luogu ...

  6. 少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小

    少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写 ...

  7. BZOJ3065 带插入区间K小值 || 洛谷P4278

    这是一道让我崩溃的题...... 然鹅洛谷上时限被改然后只有20分......好像所有人都被卡了(雾) 由于替罪羊树不是依靠旋转操作而是依靠暴力重构的方式维护树的平衡,所以我们可以考虑使用替罪羊树套区 ...

  8. 【可持久化线段树】POJ2104 查询区间第k小值

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 61284   Accepted: 21504 Ca ...

  9. poj2104 K-th Number区间第k小值 主席树

    原来主席树就是可持久化线段树啊,刚知道,,, 作为一道裸题,还是必A的,然而一开始偷懒不写离散化跪了N多遍,后来在缪大的帮助下发现了这个问题,遂A之 ——又是这种破问题,实在不想说自己了 把n个数看成 ...

随机推荐

  1. v-show

    v-show的原理是当值为false的时候,元素display:none  隐藏了元素且脱离文档流,但是在dom 中仍然存在. 与v-if使用场景不同,文档中提到,当需要高频切换的时候使用v-show ...

  2. C#进阶学习笔记(个人整理)

    学习笔记 第一章: 一.回顾数组 1.变量 : 只能存储一个数据 2.数组 :存储固定大小的相同类型的数据 3.对象 : 存储多个相同/不同类型的数据 4.集合 : 特殊的容器,存储N个相同/不同类型 ...

  3. 腾讯云负载均衡CLB

    负载均衡 使用场景: ①购买一个负载均衡LB实例 ②一级.二级域名都解析到VIP上 ③创建HTTP/HTTPS监听器 ④绑定云主机 在nginx中只需要配置好伪静态和相关设置就ok了

  4. Cloudera Manager 安装 CDH5

    文档说明 本文是针对Linux CentOS6服务器与CDH5.15的安装手册. 关于CDH和ClouderaManager CDH(Cloudera's Distribution, includin ...

  5. yii2深入理解之内核解析

    一.前言 首先,yii2最为为数不多的PHP主流开源框架,受欢迎程度不亚于laravel和TP.个人认为,研究这些框架底层代码是非常有助于自身代码编程思想的提升和代码简化程度和质量的提升的. 那么,话 ...

  6. hive_异常_01_(未解决)FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. org.apache.hadoop.hbase.HTableDescriptor.addFamily(Lorg/apache/hadoop/hbase/HColumnDescriptor;)V

    一.如果出现如下错误需要编译源码 需要重新编译Hbase-handler源码 步骤如下: 准备Jar包: 将Hbase 中lib下的jar包和Hive中lib下的jar包全部导入到一起. 记得删除里面 ...

  7. bin/postconf: error while loading shared libraries: libmysqlclient

    今天在编译安装postfix的时候 make install 出现如下错误 bin/postconf: error while loading shared libraries: libmysqlcl ...

  8. HDU 5446 Unknown Treasure (卢卡斯+CRT

    代码: #include"bits/stdc++.h" #define db double #define ll long long #define vec vector<l ...

  9. HyperLedger Fabric 1.4 区块链技术定义(2.1)

    区块链技术指使用点对点传输.共识机制.加密算法等技术,保证分布式数据库区块写入链中数据的一致性,达到去中心化和不可篡改的目的.       区块链就是一种特殊的分布式数据库,使用现有的各种成熟的技术, ...

  10. 13、python中的函数(闭包与装饰器)

    一.嵌套函数 函数的内部又再定义另一个函数,这个函数就叫嵌套函数,里面含函数就叫内部函数. 示例: 二.返回函数 函数可以接收函数对象作为参数,同理函数也能返回一个函数对象作为返回值. 示例: 返回函 ...