洛谷题目传送门

YCB巨佬对此题有详细的讲解。%YCB%请点这里

思路分析

不能套用静态主席树的方法了。因为的\(N\)个线段树相互纠缠,一旦改了一个点,整个主席树统统都要改一遍。。。。。。

话说我真的快要忘了有一种数据结构,能支持单点修改,区间查询,更重要的是,常数优秀的它专门用来高效维护前缀和!!它就是——

!树状数组!

之前静态主席树要保存的每个线段树\([1,i]\),不也是一个庞大的前缀吗?于是,把树状数组套在线段树上,构成支持动态修改的主席树。每个树状数组的节点即为一个线段树的根节点。

举个栗子,维护一个长度为\(5\)的序列,树状数组实际会长成这样——

于是就利用树状数组来维护前缀和了。首先是修改(设修改元素位置为\(i\))。从下标为\(i\)的树状数组节点开始,每次都往后跳(+=lowbit(i)),所有跳到的线段树都改一遍,原值对应区间-1,新值对应区间+1。一共要改\(log\)棵树。

然后是查询。先把\(l-1\)和\(r\)都往前跳(-=lowbit(i)),每次跳到的都记下来。求当前\(size\)的时候,用记下来的\(log\)棵由\(r\)得到的节点左儿子的\(size\)和(就代表\([1,r]\)的\(size\))减去\(log\)棵由\(l-1\)得到的节点左儿子的\(size\)和(就代表\([1,l-1]\)的\(size\))就是\([l,r]\)的\(size\)。往左/右儿子跳的时候也是\(log\)个节点一起跳。

其实还有一个问题,一开始本蒟蒻想不通,就是\(N\)棵线段树已经无法共用内存了,那空间复杂度不会是\(O(N^2\log N)\)吗?

其实没必要担心的。。。。。。

只考虑修改操作,每次有\(log\)棵线段树被挑出来,每个线段树只修改\(log\)个节点,因此程序一趟跑下来,仅有\(N\log^2N\)个节点被访问过,我们只需要动态开点就好了。

下面贴代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. #define R register int
  6. const int N=10009,M=4000009;//M:开Nlog²的空间
  7. bool op[N];
  8. int L,P,n,a[N],b[N],c[N],d[N],g[N<<1];
  9. int rt[N],lc[M],rc[M],s[M];
  10. int pl,pr,reql[20],reqr[20];
  11. #define G ch=getchar()
  12. #define GO G;while(ch<'-')G
  13. #define in(z) GO;z=ch&15;G;while(ch>'-')z*=10,z+=ch&15,G
  14. inline void update(R p,R v)//修改
  15. {
  16. R k=lower_bound(g+1,g+L+1,a[p])-g;//先找到离散化后对应值
  17. for(R i=p;i<=n;i+=i&-i)
  18. {
  19. R*t=&rt[i],l=1,r=L,m;
  20. while(l!=r)
  21. {
  22. if(!*t)*t=++P;//动态分配空间
  23. s[*t]+=v;
  24. m=(l+r)>>1;
  25. if(k<=m)r=m,t=&lc[*t];
  26. else l=m+1,t=&rc[*t];
  27. }
  28. if(!*t)*t=++P;
  29. s[*t]+=v;
  30. }
  31. }
  32. inline int ask(R l,R r,R k)
  33. {
  34. R i,m,sum;
  35. pl=pr=0;
  36. for(i=l-1;i;i-=i&-i)
  37. reql[++pl]=rt[i];
  38. for(i=r;i;i-=i&-i)
  39. reqr[++pr]=rt[i];//需要查询的log个线段树全记下来
  40. l=1;r=L;
  41. while(l!=r)
  42. {
  43. m=(l+r)>>1;sum=0;
  44. for(i=1;i<=pr;++i)sum+=s[lc[reqr[i]]];
  45. for(i=1;i<=pl;++i)sum-=s[lc[reql[i]]];//一起加一起减
  46. if(k<=sum)
  47. {
  48. for(i=1;i<=pl;++i)reql[i]=lc[reql[i]];
  49. for(i=1;i<=pr;++i)reqr[i]=lc[reqr[i]];
  50. r=m;
  51. }//一起向同一边儿子跳
  52. else
  53. {
  54. for(i=1;i<=pl;++i)reql[i]=rc[reql[i]];
  55. for(i=1;i<=pr;++i)reqr[i]=rc[reqr[i]];
  56. l=m+1;k-=sum;
  57. }
  58. }
  59. return g[l];
  60. }
  61. int main()
  62. {
  63. register char ch;
  64. R m,i;
  65. in(n);in(m);L=n;
  66. for(i=1;i<=n;++i){in(a[i]);}
  67. memcpy(g,a,(n+1)<<2);
  68. for(i=1;i<=m;++i)
  69. {
  70. GO;op[i]=ch=='Q';
  71. in(b[i]);in(c[i]);
  72. if(op[i]){in(d[i]);}
  73. else g[++L]=c[i];//变成动态的了,离散化时后面需要修改的值也要考虑进去,所以先把所有操作保存起来
  74. }
  75. sort(g+1,g+L+1);
  76. L=unique(g+1,g+L+1)-g-1;//离散化
  77. for(i=1;i<=n;++i)update(i,1);//一开始还是每个点都要更新一遍
  78. for(i=1;i<=m;++i)
  79. {
  80. if(op[i])printf("%d\n",ask(b[i],c[i],d[i]));
  81. else
  82. {
  83. update(b[i],-1);//注意被替代的以前那个值要减掉
  84. a[b[i]]=c[i];
  85. update(b[i],1);
  86. }
  87. }
  88. return 0;
  89. }

洛谷P2617 Dynamic Ranking(主席树,树套树,树状数组)的更多相关文章

  1. 洛谷P2617 Dynamic Rankings (主席树)

    洛谷P2617 Dynamic Rankings 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a ...

  2. 洛谷P2617 Dynamic Rankings 主席树 单点修改 区间查询第 K 大

    我们将线段树套在树状数组上,查询前预处理出所有要一起移动的节点编号,并在查询过程中一起将这些节点移到左右子树上. Code: #include<cstdio> #include<cs ...

  3. 洛谷 P2617 Dynamic Ranking

    题目描述 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤ ...

  4. 2018.07.01洛谷P2617 Dynamic Rankings(带修主席树)

    P2617 Dynamic Rankings 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i ...

  5. 洛谷 P2617 Dynamic Rankings || ZOJ - 2112

    写的让人看不懂,仅留作笔记 静态主席树,相当于前缀和套(可持久化方法构建的)值域线段树. 建树方法:记录前缀和的各位置的线段树的root.先建一个"第0棵线段树",是完整的(不需要 ...

  6. 洛谷P2617 Dynamic Rankings

    带修主席树模板题 主席树的单点修改就是把前缀和(大概)的形式改成用树状数组维护,每个树状数组的元素都套了一个主席树(相当于每个数组的元素root[i]都是主席树,且这个主席树维护了(i - lowbi ...

  7. 洛谷 P2617 Dynamic Rankings 解题报告

    P2617 Dynamic Rankings 题目描述 给定一个含有\(n\)个数的序列\(a[1],a[2],a[3],\dots,a[n]\),程序必须回答这样的询问:对于给定的\(i,j,k\) ...

  8. 洛谷$P2617\ Dynamic\ Rankings$ 整体二分

    正解:整体二分 解题报告: 传送门$w$ 阿查询带修区间第$k$小不显然整体二分板子呗,,, 就考虑先按时间戳排序(,,,其实并不需要读入的时候就按着时间戳排的鸭$QwQ$ 每次二分出$mid$先把所 ...

  9. 【小技巧】树剖套线段树优化建图如何做到 O(nlogn)

    前提:用树剖套线段树优化树链连边.例题:bzoj4699 我们说树剖的时间复杂度是 $O(n\times log(n))$,是因为访问一条链时需要经过 $log(n)$ 级别条重链,对于每条重链还需要 ...

随机推荐

  1. LeetCode - 657. Judge Route Circle

    Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if this robot m ...

  2. Spring Boot让开发如此简单

    从html到asp后一直专注.net开发,从.net诞生到如今,从winform到webform,从asp.net到.net mcv,从.net mvc到.net core,从ado.net到linq ...

  3. 记录一次CentOS环境升级Python2.6到Python2.7并安装最新版pip

    背景介绍 一次实验中需要安装python-etcd包.安装这个包时要求的python和pip版本比目前系统的版本高. 系统是centos6.6    64位 1 2 3 4 5 6 7 [root@m ...

  4. Linux下绝对经典的命令

    1.使用远程终端时,可以使用如下命令: screen tmux 2.下载文件可以使用如下命令: curl wget 3.压缩解压缩可以使用: tar .zip.rar 4.使用抓包工具 tcpdump ...

  5. nginx 浏览php的时候会变成下载

    php的时候会变成下载:这是因为nginx没有设置好碰到php文件时,要传递到后方的php解释器.看看你的nginx.conf配置,里面有没有这样的设置:location ~ .*\.php$ {fa ...

  6. 中小研发团队架构实践之应用监控Metrics

    一.Metrics简介        应用监控系统Metrics由Metrics.NET+InfluxDB+Grafana组合而成,通过客户端Metrics.NET在业务代码中埋点,Metrics.N ...

  7. web2 - JavaScript

    JavaScript 知识要点 参考教材一 参考教材二 参考教材三 1.JavaScript 和 Java 的关系? 2.JavaScript 在编程中可以做什么? 3.如何在 html 中使用 Ja ...

  8. 项目中AppDelegate详解

    1.AppDelegate.h //模板默认引入程序需要使用“类”的框架,即UIKit.h头文件,使它包含在程序中 #import <UIKit/UIKit.h> //此处@class声明 ...

  9. Python实现二分查找

    老生常谈的算法了. #!/usr/bin/python # -*- coding:utf-8 -*- # Filename: demo.py # 用python实现二分查找 def binarySea ...

  10. Ansible自动化运维笔记2(Ansible的组件介绍)

    1.Ansible Inventory (1)静态主机文件 默认的ansible invetory是/etc/hosts文件,可以通过ANSIBLE_HOSTS环境变量或者通过运行命令的时候加上-i ...