ZOJ - 2112

\[\
\]

(那些说这道题是树状数组套主席树的人一定对主席树有误解!)

这里我们用树状数组套线段树来解决来写

首先 , 我们需要有n棵线段树(不是\(n^2\)空间,别慌)

我们用这些线段树存储值域$ [l,r] $内数的个数

基于主席树的思想,我们的线段树是要相减的,记录的是前缀

由于要更新前缀,我们必须快速更新,所以采用树状数组来写

事实上,这里线段树的本质并非主席树,而是动态开点的线段树

(这两者是有显著差异的)

这是主席数的单点修改

  1. struct Functional_SegmentTree{
  2. void Add(int p,int pre,int l,int r,int x,int y){
  3. s[p]=s[pre]+y;
  4. if(l==r) return;
  5. int mid=(l+r)>>1;
  6. if(x<=mid) rs[p]=rs[pre],Add(ls[p]=++cnt,ls[pre],l,mid,x,y);
  7. else ls[p]=ls[pre],Add(rs[p]=++cnt,rs[pre],mid+1,r,x,y);
  8. }
  9. };

是路径上的所有点都要新开节点,而实际上动点线段树不是开新点,只是当你的儿子要访问了却还未开出来时才需要开

所以代码应该是这样的

  1. void Add(int p,int l,int r,int x,int y){
  2. s[p]+=y;
  3. if(l==r) return;
  4. int mid=(l+r)>>1;
  5. if(x<=mid) Add(ls[p]?ls[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,ls[p]=++cnt),l,mid,x,y);
  6. else Add(rs[p]?rs[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,rs[p]=++cnt),mid+1,r,x,y);
  7. }

(略有压行)

所以整体上应该是树状数组更新动点线段树

但是由于这题卡空间 (过于罪恶)

所以我们应该先开一个主席树存下原来的值

(为什么这样能省空间呢?因为树状数组更新的空间复杂度是\(log^2(n)\),主席树更新是log(n)的)

于是代码会长这样

  1. const int N=50100,M=10010,K=1520110;
  2. int n,m;
  3. int ncnt;
  4. int a[N],b[N+M],c[M],d[M],e[M];
  5. int cnt;
  6. int ls[K],rs[K],s[K];
  7. int rt[N];
  8. struct hjt{
  9. void Add(int p,int pre,int l,int r,int x,int y){
  10. s[p]=s[pre]+y;
  11. if(l==r) return;
  12. int mid=(l+r)>>1;
  13. if(x<=mid) rs[p]=rs[pre],Add(ls[p]=++cnt,ls[pre],l,mid,x,y);
  14. else ls[p]=ls[pre],Add(rs[p]=++cnt,rs[pre],mid+1,r,x,y);
  15. }
  16. }H;
  17. struct sts{
  18. void Add(int p,int l,int r,int x,int y){
  19. s[p]+=y;
  20. if(l==r) return;
  21. int mid=(l+r)>>1;
  22. if(x<=mid) Add(ls[p]?ls[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,ls[p]=++cnt),l,mid,x,y);
  23. else Add(rs[p]?rs[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,rs[p]=++cnt),mid+1,r,x,y);
  24. }
  25. int T[N];
  26. vector <int> X,Y;
  27. int Que(int l,int r,int k){
  28. if(l==r) return l;
  29. int mid=(l+r)>>1;
  30. int t=0;
  31. rep(i,0,X.size()-1) t+=s[ls[X[i]]];
  32. rep(i,0,Y.size()-1) t-=s[ls[Y[i]]];
  33. if(t>=k) {
  34. rep(i,0,X.size()-1) X[i]=ls[X[i]];
  35. rep(i,0,Y.size()-1) Y[i]=ls[Y[i]];
  36. return Que(l,mid,k);
  37. } else {
  38. rep(i,0,X.size()-1) X[i]=rs[X[i]];
  39. rep(i,0,Y.size()-1) Y[i]=rs[Y[i]];
  40. return Que(mid+1,r,k-t);
  41. }
  42. }
  43. int query(int l,int r,int k){
  44. int p=r; X.clear();X.push_back(rt[r]);
  45. while(p) X.push_back(T[p]),p-=p&-p;
  46. p=l-1;Y.clear();Y.push_back(rt[l-1]);
  47. while(p) Y.push_back(T[p]),p-=p&-p;
  48. return Que(1,ncnt,k);
  49. }
  50. void Upd(int p,int x,int y){
  51. while(p<=n) Add(T[p]?T[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,T[p]=++cnt),1,ncnt,x,y),p+=p&-p;
  52. }
  53. }S;
  54. char opt[N][1];
  55. int main(){
  56. rep(kase,1,rd()){
  57. n=rd(),m=rd();
  58. cnt=0; memset(S.T,0,sizeof S.T);
  59. rep(i,1,n) a[i]=b[i]=rd();
  60. ncnt=n;
  61. rep(i,1,m) {
  62. scanf("%s",opt[i]);
  63. if(opt[i][0]=='Q'){
  64. c[i]=rd(),d[i]=rd(),e[i]=rd();
  65. } else {
  66. c[i]=rd(),d[i]=rd();
  67. b[++ncnt]=d[i];
  68. }
  69. }
  70. sort(b+1,b+ncnt+1);ncnt=unique(b+1,b+ncnt+1)-b-1;
  71. rep(i,1,n) {
  72. a[i]=lower_bound(b+1,b+ncnt+1,a[i])-b;
  73. H.Add(rt[i]=++cnt,rt[i-1],1,ncnt,a[i],1);
  74. }
  75. rep(i,1,m){
  76. if(opt[i][0]=='Q'){
  77. int ans=S.query(c[i],d[i],e[i]);
  78. printf("%d\n",b[ans]);
  79. }else {
  80. d[i]=lower_bound(b+1,b+ncnt+1,d[i])-b;
  81. S.Upd(c[i],a[c[i]],-1);
  82. S.Upd(c[i],a[c[i]]=d[i],1);
  83. }
  84. }
  85. }
  86. }

Dynamic_Rankings(动态区间第k大)的更多相关文章

  1. ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】

    题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题意: 求动态区间第K大. 分析: 把修改操作看成删除与增加 ...

  2. hdu5412(动态区间第k大)

    CRB and Queries Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Other ...

  3. ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)

    题目大意 给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类: 1. 修改数列中某个位置的数的值为 val 2. 询问 [L, R] 这个区间中第 k 大的是多少 n<=50,00 ...

  4. ZOJ2112--Dynamic Rankings (动态区间第k大)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  5. 整体二分求动态区间第k大

    比树状数组套主席树不知道高到哪里去了,solve(l,r,L,R)就是对于L,R的操作区间的答案都在l,r区间里,然后递归下去 复杂度O(nlognlogn),每个操作会执行logn次就是o(nlog ...

  6. 动态区间第K大

    整体二分. 主要需要注意的一点是,对于每个删除操作,若删除操作被算入贡献,则最开始的插入操作也一定会被算入,所以不必担心删除删错. #include<cstdio> #include< ...

  7. 整体二分(模板二)动态区间第K大

    这才是更一般的二分写法--HDU5412 #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #include <cstdio>// ...

  8. 静态区间第k大(主席树)

    POJ 2104为例(主席树入门题) 思想: 可持久化线段树,也叫作函数式线段树,也叫主席树(高大上). 可持久化数据结构(Persistent data structure):利用函数式编程的思想使 ...

  9. 【ZOJ2112】【整体二分+树状数组】带修改区间第k大

    The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with t ...

随机推荐

  1. javascript原型深入解析2--Object和Function,先有鸡先有蛋

    1.提出两个问题: Js 的prototype和__proto__ 是咋回事? 先有function 还是先有object? 2.引用<JavaScript权威指南>的一段描述: 每个JS ...

  2. 使用Nginx 对Laravel 进行负载

    项目环境php7.2, nginx , Laravel,开发的微信公众号应用 .目前访问量的上升,单台服务器不能满足需求,于是用nginx做了负载.以下是一种可行性方案,目前正在使用. session ...

  3. Matlab解释器模式

    解释器模式(Interperter),给定一个语言,定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,实际开发中EL表达式或者正则表达式的解释器就是采用这种设计模式.其模式结构如下图.本文使 ...

  4. npm安装时-S -D作用及区别

    -S 即--save(保存) 包名会被注册在package.json的dependencies里面,在生产环境下这个包的依赖依然存在 -D 即--dev(生产) 包名会被注册在package.json ...

  5. android shap画圆(空心圆、实心圆)

    实心圆: <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android=" ...

  6. 小程序mpvue怎么点击按钮获取button里面的值

    在小程序里面是没有dom元素的,这个我们只要会小程序的应该都知道,但是在平时开发中我们偶尔会遇到需要点击某个元素获取它的值的情况,在这里给大家列举了两种情况解决方法 方式一:数据绑定 这种情况的话,对 ...

  7. 英语gzibeads天珠gzibeads单词

    天珠英语是gZiBeads,藏语叫(si , 斯)汉语译为“斯”或“瑟”,又称“天降石”.在<藏汉大辞典>里天珠的解释为:“亚玛瑙,猫睛石,一种宝石,俗称九眼珠.入药能治脑溢血”.最早的天 ...

  8. RPC相关知识

    为什么要进行系统拆分,为什么要用dubbo RPC的由来,基本架构,实现原理,整个调用过程经历了哪几步 Java动态代理及 RPC框架介绍 一篇文章了解RPC框架原理 dubbo详解及demo实例 d ...

  9. JAVA Coder 的《深入分析Java Web 技术内幕》读书笔记

    本文基于<深入分析Java Web 技术内幕> <深入分析Java Web 技术内幕>,作者是 许令波,电子工业出版社.本文只是记录书本当中的精彩部分,作个人回顾和技术分享,请 ...

  10. Python:基础复习

    一.数据类型 对象的三大特征:值.身份.类型: 1)数字 Number 整型.浮点型 只有 int 和 float 两种类型: type(2/2):float 类型:2/2 == 1.0: type( ...