您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

应xgy的邀来码树套树了...今天或许能码完这一篇吧...还在发烧,动态区间第k大(权值线段树套线段树or树状数组套主席树)估计码不完了

所以正好分成几天来写,写的细一点

这种题一般很明显...就是又有平衡树性质又有线段树性质应该就是线段树套平衡树了吧

顾名思义,线段树套平衡树,就是对于线段树的每一个点开一个平衡树,利用平衡树的灵活性和线段树对区间处理的强大来解决问题

简单的来说,原来线段树每个点是一个区间,你用平衡树维护每个区间,最后的得到的就是线段树套平衡树

怎么样,理论非常简单吧    然而写起来难的一匹我会说?

来看一下这道题

OPT1:线段树常规查询区间,每一次统计小于k的点的个数再相加。 
OPT2:这个是最麻烦也是最精妙的一问,解决方法是二分答案,每二分到一个答案查询一下这个答案在这个区间内的排名,如果排名等于k+1的话返回它的pre即可。注意这里二分满足条件之后不用查询pre,答案直接为left-1,可以证明left-1一定在序列中。 
OPT3:相当于线段树的点修改,在平衡树中删除再插入即可。 
OPT4:线段树常规查询区间,每一次找区间内比k小的最大的数,然后取max 
OPT5:类似于OPT4,每一次找区间内比k大的最小的数,然后取min

大概就是这样了吧- -#

懒得写SBT,拿splay卡时限过的

大家写SBT或者Treap都是极好的,千万不要学我

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<cstring>
  7. #include<vector>
  8. #include<queue>
  9. using namespace std;
  10. const int maxn=4e6+;
  11. const int inf=;
  12. int ans;
  13. int a[maxn];
  14. int n,m;
  15. struct Seg_Tao_Splay//原代码是分开写的...但是太丑了
  16. {
  17. int fa[maxn],size[maxn],son[maxn][],key[maxn],rt[maxn],cnt[maxn],Size;
  18. inline int gt(int x){return son[fa[x]][]==x;}
  19. inline void pushup(int x){size[x]=cnt[x]+size[son[x][]]+size[son[x][]];}
  20. inline void sclear(int x){fa[x]=son[x][]=son[x][]=size[x]=cnt[x]=key[x]=;}
  21. inline void rotate(int x)
  22. {
  23. int f1=fa[x],f2=fa[f1],wt=gt(x);
  24. son[f1][wt]=son[x][wt^];
  25. fa[son[f1][wt]]=f1;
  26. son[x][wt^]=f1;
  27. fa[f1]=x;
  28. if (f2) son[f2][son[f2][]==f1]=x;
  29. fa[x]=f2;
  30. pushup(f1);
  31. pushup(x);
  32. }
  33. inline void Splay(int x)
  34. {
  35. for(int faf;faf=fa[x];rotate(x))
  36. if(fa[faf])
  37. rotate((gt(x)==gt(faf))?faf:x);
  38. }
  39. inline void sinsert(int i,int x)//在Splay里加点
  40. {
  41. int now=rt[i],faf=;
  42. if (!rt[i])
  43. {
  44. rt[i]=++Size;
  45. fa[Size]=son[Size][]=son[Size][]=;
  46. size[Size]=cnt[Size]=; key[Size]=x;
  47. return;
  48. }
  49. while("woxihuankeduoli")
  50. {
  51. if (x==key[now])
  52. {
  53. cnt[now]++;
  54. pushup(faf);
  55. Splay(now);
  56. rt[i]=now;
  57. return;
  58. }
  59. faf=now;
  60. now=son[now][key[now]<x];
  61. if(!now)
  62. {
  63. ++Size;
  64. fa[Size]=faf; son[Size][]=son[Size][]=;
  65. size[Size]=cnt[Size]=; key[Size]=x;
  66. son[faf][key[faf]<x]=Size;
  67. pushup(faf);
  68. Splay(Size);
  69. rt[i]=Size;
  70. return;
  71. }
  72. }
  73. }
  74. inline void sfind(int i,int x)
  75. {
  76. int now=rt[i];
  77. while (){
  78. if (key[now]==x)
  79. {
  80. Splay(now);
  81. rt[i]=now;
  82. return;
  83. }
  84. else if (key[now]>x) now=son[now][];
  85. else if (key[now]<x) now=son[now][];
  86. }
  87. }
  88. inline int spre(int i)
  89. {
  90. int now=son[rt[i]][];
  91. while (son[now][]) now=son[now][];
  92. return now;
  93. }
  94. inline int snext(int i)
  95. {
  96. int now=son[rt[i]][];
  97. while (son[now][]) now=son[now][];
  98. return now;
  99. }
  100. inline void sdel(int i)
  101. {
  102. int now=rt[i];
  103. if (cnt[now]>)
  104. {
  105. cnt[now]--;
  106. pushup(now);
  107. return;
  108. }
  109. if (!son[now][]&&!son[now][])
  110. {
  111. sclear(rt[i]);
  112. rt[i]=;
  113. return;
  114. }
  115. if (!son[now][])
  116. {
  117. int prert=now;
  118. rt[i]=son[prert][];
  119. fa[rt[i]]=;
  120. sclear(prert);
  121. return;
  122. }
  123. if (!son[now][])
  124. {
  125. int prert=now;
  126. rt[i]=son[prert][];
  127. fa[rt[i]]=;
  128. sclear(prert);
  129. return;
  130. }
  131. int leftM=spre(i),prert=rt[i];
  132. Splay(leftM); rt[i]=leftM;
  133. son[rt[i]][]=son[prert][];
  134. fa[son[prert][]]=rt[i];
  135. sclear(prert);
  136. pushup(rt[i]);
  137. return;
  138. }
  139. inline int sfindrank(int i,int x)
  140. {
  141. int now=rt[i],ans=;
  142. while ()
  143. {
  144. if (!now) return ans;
  145. if (key[now]==x) return ((son[now][])?size[son[now][]]:)+ans;
  146. else if (key[now]<x)
  147. {
  148. ans+=((son[now][])?size[son[now][]]:)+cnt[now];
  149. now=son[now][];
  150. }
  151. else if (key[now]>x) now=son[now][];
  152. }
  153. }
  154. inline int sfindpre(int i,int k)
  155. {
  156. int now=rt[i];
  157. while (now)
  158. {
  159. if (key[now]<k)
  160. {
  161. if (ans<key[now])ans=key[now];
  162. now=son[now][];
  163. }
  164. else now=son[now][];
  165. }
  166. return ans;
  167. }
  168. inline int sfindnext(int i,int k)
  169. {
  170. int now=rt[i];
  171. while (now)
  172. {
  173. if (key[now]>k)
  174. {
  175. if (ans>key[now]) ans=key[now];
  176. now=son[now][];
  177. }
  178. else now=son[now][];
  179. }
  180. return ans;
  181. }
  182. //以上为splay操作 下面是线段树操作
  183. inline void insertSeg(int id,int l,int r,int x,int v)
  184. {
  185. int mid=(l+r)>>;
  186. sinsert(id,v);
  187. if (l==r) return;
  188. if (x<=mid) insertSeg(id<<,l,mid,x,v);
  189. else insertSeg(id<<|,mid+,r,x,v);
  190. }
  191. inline void askrankSeg(int id,int l,int r,int lrange,int rrange,int k)
  192. {
  193. int mid=(l+r)>>;
  194. if (lrange<=l&&r<=rrange)
  195. {
  196. ans+=sfindrank(id,k);
  197. return;
  198. }
  199. if (lrange<=mid) askrankSeg(id<<,l,mid,lrange,rrange,k);
  200. if (mid+<=rrange) askrankSeg(id<<|,mid+,r,lrange,rrange,k);
  201. }
  202. inline void changeSeg(int id,int l,int r,int x,int k)
  203. {
  204. int mid=(l+r)>>;
  205. sfind(id,a[x]); sdel(id); sinsert(id,k);
  206. if (l==r) return;
  207. if (x<=mid) changeSeg(id<<,l,mid,x,k);
  208. else changeSeg(id<<|,mid+,r,x,k);
  209. }
  210. inline void askpreSeg(int id,int l,int r,int lrange,int rrange,int k)
  211. {
  212. int mid=(l+r)>>;
  213. if (lrange<=l&&r<=rrange)
  214. {
  215. ans=max(ans,sfindpre(id,k));
  216. return;
  217. }
  218. if (lrange<=mid) askpreSeg(id<<,l,mid,lrange,rrange,k);
  219. if (mid+<=rrange) askpreSeg(id<<|,mid+,r,lrange,rrange,k);
  220. }
  221. inline void asknextSeg(int id,int l,int r,int lrange,int rrange,int k)
  222. {
  223. int mid=(l+r)>>;
  224. if (lrange<=l&&r<=rrange)
  225. {
  226. ans=min(ans,sfindnext(id,k));
  227. return;
  228. }
  229. if (lrange<=mid) asknextSeg(id<<,l,mid,lrange,rrange,k);
  230. if (mid+<=rrange) asknextSeg(id<<|,mid+,r,lrange,rrange,k);
  231. }
  232. }Tree;
  233. int _max=-;
  234. int opt,l,r,k,le,ri,md;
  235. int main()
  236. {
  237. scanf("%d%d",&n,&m);
  238. for(int i=;i<=n;i++){scanf("%d",&a[i]);_max=max(_max,a[i]);Tree.insertSeg(,,n,i,a[i]);}
  239. for(int i=;i<=m;i++)
  240. {
  241. scanf("%d",&opt);
  242. if(opt==)
  243. {
  244. scanf("%d%d%d",&l,&r,&k);
  245. ans=;
  246. Tree.askrankSeg(,,n,l,r,k);
  247. printf("%d\n",ans+);
  248. }
  249. if(opt==)
  250. {
  251. scanf("%d%d%d",&l,&r,&k);
  252. le=,ri=_max+;
  253. while(le!=ri)
  254. {
  255. md=(le+ri)>>;
  256. ans=;
  257. Tree.askrankSeg(,,n,l,r,md);
  258. if(ans<k)le=md+;
  259. else ri=md;
  260. }
  261. printf("%d\n",le-);
  262. }
  263. if(opt==)
  264. {
  265. scanf("%d%d",&l,&k);
  266. Tree.changeSeg(,,n,l,k);
  267. a[l]=k;
  268. _max=max(_max,k);
  269. }
  270. if(opt==)
  271. {
  272. scanf("%d%d%d",&l,&r,&k);ans=-;
  273. Tree.askpreSeg(,,n,l,r,k);
  274. printf("%d\n",ans);
  275. }
  276. if(opt==)
  277. {
  278. scanf("%d%d%d",&l,&r,&k);ans=;
  279. Tree.asknextSeg(,,n,l,r,k);
  280. printf("%d\n",ans);
  281. }
  282. }
  283. }

线段树套平衡树很简单(思想层面)但它是我们学习树套树的基础,建议仔细学习一个,然后做以下例题。

这个东西练熟了,我们就可以更好的了解其他形式的树套树,我们还可以更好的形成"树套树"的思想

这个思想有助于我们写出很多数据结构毒瘤题的正解/暴力

例题:

bzoj2141  排队   注:此题线段树套平衡树略难,可以参考网上的分块套树状数组做法

bzoj1901  ZOJ2112 Dynamic Rankings    注:此题也叫“可持久化主席树”所以绝对有树状数组套主席树的做法

bzoj2120  数颜色   注:正解带修改莫队

题解我会慢慢写,毕竟树套树写一个也不是那么简单啊QAQ

树套树Day1线段树套平衡树bzoj3196的更多相关文章

  1. luogu3380/bzoj3196 二逼平衡树 (树状数组套权值线段树)

    带修改区间K大值 这题有很多做法,我的做法是树状数组套权值线段树,修改查询的时候都是按着树状数组的规则找出那log(n)个线段树根,然后一起往下做 时空都是$O(nlog^2n)$的(如果离散化了的话 ...

  2. 【bzoj3065】带插入区间K小值 替罪羊树套权值线段树

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

  3. BZOJ2141排队——树状数组套权值线段树(带修改的主席树)

    题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家 乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别 ...

  4. CF1093E Intersection of Permutations 树状数组套权值线段树

    \(\color{#0066ff}{ 题目描述 }\) 给定整数 \(n\) 和两个 \(1,\dots,n\) 的排列 \(a,b\). \(m\) 个操作,操作有两种: \(1\ l_a\ r_a ...

  5. Dynamic Rankings(树状数组套权值线段树)

    Dynamic Rankings(树状数组套权值线段树) 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[ ...

  6. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

  7. 【BZOJ3196】二逼平衡树(树状数组,线段树)

    [BZOJ3196]二逼平衡树(树状数组,线段树) 题面 BZOJ题面 题解 如果不存在区间修改操作: 搞一个权值线段树 区间第K大--->直接在线段树上二分 某个数第几大--->查询一下 ...

  8. NOIp 数据结构专题总结 (2):分块、树状数组、线段树

    系列索引: NOIp 数据结构专题总结 (1) NOIp 数据结构专题总结 (2) 分块 阅:<「分块」数列分块入门 1-9 by hzwer> 树状数组 Binary Indexed T ...

  9. 树(一)——线段树

    问题 现在有1~30这30个数,数N被抽上的概率正比于1/sqrt(N+1),求满足这个概率分布的随机数发生器. 思路 第一,如何解决这个"概率正比"问题. 第二,如何产生满足条件 ...

随机推荐

  1. Largest Rectangle in a Histogram (最大子矩阵)

    hdu 1506 A histogram is a polygon composed of a sequence of rectangles aligned at a common base line ...

  2. 【Emit】关于System.MethodAccessException解决方案

        最近学习Emit,在使用Emit动态生成对象时碰到一些"蛋疼"的问题,如下: 1.安全透明方法"XXX.XX()"尝试访问安全关键方法"YYY ...

  3. Java NIO Buffer(netty源码死磕1.2)

    [基础篇]netty源码死磕1.2:  NIO Buffer 1. Java NIO Buffer Buffer是一个抽象类,位于java.nio包中,主要用作缓冲区.Buffer缓冲区本质上是一块可 ...

  4. 【译】快速高效学习Java编程在线资源Top 20

    想要加强你的编程能力吗?想要提升你的 Java 编程技巧和效率吗? 不用担心.本文将会提供快速高效学习 Java 编程的 50 多个网站资源: 开始探索吧: 1.MKyong:许多开发者在这里可以找到 ...

  5. R语言数据管理(五)

    一.数据的输入: 手动输入:edit( )函数 也可修改 mydata <- data.frame(age=numeric(0),gender=character(0),weight=numer ...

  6. Linux命令:grep,报错Binary file (standard input) matches

    在Linux使用grep命令,从文件中抓取显示特定的信息,如下: cat 文件名 | grep 特定条件 --->   cat xxxx | grep 12345 结果报错:Binary fil ...

  7. 通过systemd配置Docker

    1. systemd Service相关目录 通常情况下,我们有3种方式可以配置etcd中的service.以docker为例,1)在目录/etc/systemd/system/docker.serv ...

  8. 请简单介绍一下Spring

    Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架. Spring ...

  9. vue页面性能优化方案

    个人在项目中用到的页面性能优化的方式总结. 一.均衡页面加载文件的大小和数量 1.项目中小图片图片转base64,通过工具如webpack进行图片压缩,文件进行压缩混淆等 2.vue-router 懒 ...

  10. mysql日志总结

    1.mysql慢查询设置 log-slow-queries=/alidata/mysql-log/mysql-slow.loglong_query_time = 1log-queries-not-us ...