第一道主席树~然而是道比较水的。。。因为它不用修改。。。

转载一个让我看懂的主席树的讲解吧:http://blog.csdn.net/regina8023/article/details/41910615 (未授权,侵权删)

---------------------------------------------------------------------------------------------------------------------

那么如果要询问i-j之间数字出现的次数怎么办呢?

因为每一棵线段树的区间都是相同的,所以要求l-r之间的数字的出现次数只要用前r位出现的次数减去前l-1位出现的次数,就是ans

但是如果有修改操作怎么办?

如果沿用上面的做法,那么修改操作是O(nlogn)的,查询是O(1)的,修改要花好长时间。。。

前缀和联想到了树状数组,那么将前缀和用树状数组维护的话修改是O(logn*logn),查询时O(logn),查询的时间虽然变长,但是修改的时间缩短许多!!

注意:

函数式线段树的数组要开大一点!!

---------------------------------------------------------------------------------------------------------------------

这题就是模版题啦,先离散,求区间第k大的时候lx=root[l-1],rx=root[r],两边同时走不断作差,看看左孩子的数量,如果k更大就减掉左孩子的到有右孩子中找。

代码:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<algorithm>
  7. using namespace std;
  8.  
  9. const int N=,INF=(int)1e9+;
  10. struct trnode{
  11. int lc,rc,cnt;
  12. }t[*N];
  13. struct node{
  14. int d,id;
  15. }p[N];
  16. int n,m,tl,mx;
  17. int a[N],num[N],root[N];
  18.  
  19. bool cmp(node x,node y){return x.d<y.d;}
  20.  
  21. int bt(int l,int r)
  22. {
  23. int x=++tl;
  24. // a[x].l=l;a[x].r=r;
  25. t[x].lc=t[x].rc=;
  26. t[x].cnt=;
  27. if(l<r)
  28. {
  29. int mid=(l+r)/;
  30. t[x].lc=bt(l,mid);
  31. t[x].rc=bt(mid+,r);
  32. }
  33. return x;
  34. }
  35.  
  36. int add(int rt,int x)
  37. {
  38. int now=++tl,tmp=now;
  39. t[now].cnt=t[rt].cnt+;
  40. int l=,r=mx,mid;
  41. while(l<r)
  42. {
  43. mid=(l+r)/;
  44. if(x<=mid)
  45. {
  46. t[now].lc=++tl;
  47. t[now].rc=t[rt].rc;
  48. rt=t[rt].lc;
  49. now=tl;
  50. r=mid;
  51. }
  52. else
  53. {
  54. t[now].lc=t[rt].lc;
  55. t[now].rc=++tl;
  56. rt=t[rt].rc;
  57. now=tl;
  58. l=mid+;
  59. }
  60. t[now].cnt=t[rt].cnt+;
  61. }
  62. return tmp;
  63. }
  64.  
  65. int query(int lx,int rx,int k)
  66. {
  67. int l=,r=mx,mid;
  68. while(l<r)
  69. {
  70. mid=(l+r)/;
  71. if(t[t[rx].lc].cnt-t[t[lx].lc].cnt>=k)
  72. {
  73. r=mid;
  74. lx=t[lx].lc;
  75. rx=t[rx].lc;
  76. }
  77. else
  78. {
  79. l=mid+;
  80. k-=t[t[rx].lc].cnt-t[t[lx].lc].cnt;
  81. lx=t[lx].rc;
  82. rx=t[rx].rc;
  83. }
  84. }
  85. return l;
  86. }
  87.  
  88. void output(int x)
  89. {
  90. printf("x = %d lc = %d rc = %d cnt = %d\n",x,t[x].lc,t[x].rc,t[x].cnt);
  91. if(t[x].lc) output(t[x].lc);
  92. if(t[x].rc) output(t[x].rc);
  93. }
  94.  
  95. int main()
  96. {
  97. freopen("a.in","r",stdin);
  98. while(scanf("%d%d",&n,&m)!=EOF)
  99. {
  100. tl=;mx=;
  101. for(int i=;i<=n;i++)
  102. {
  103. scanf("%d",&a[i]);
  104. p[i].d=a[i];p[i].id=i;
  105. }
  106. sort(p+,p++n,cmp);
  107. p[].d=INF;
  108. for(int i=;i<=n;i++)
  109. {
  110. if(p[i].d!=p[i-].d) mx++,num[mx]=p[i].d;
  111. a[p[i].id]=mx;
  112. }
  113. root[]=bt(,mx);
  114. for(int i=;i<=n;i++)
  115. root[i]=add(root[i-],a[i]);
  116. // output(root[5]);
  117. for(int i=;i<=m;i++)
  118. {
  119. int l,r,k;
  120. scanf("%d%d%d",&l,&r,&k);
  121. printf("%d\n",num[query(root[l-],root[r],k)]);
  122. }
  123. }
  124. return ;
  125. }

【poj2104-求区间第k大数(不修改)】主席树/可持续化线段树的更多相关文章

  1. [csu/coj 1080]划分树求区间前k大数和

    题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数 ...

  2. 线段树专题2-(加强版线段树-可持续化线段树)主席树 orz! ------用于解决区间第k大的问题----xdoj-1216

    poj-2104(区间第K大问题) #include <iostream> #include <algorithm> #include <cstdio> #incl ...

  3. 区间前k小的和(权值线段树+离散化)--2019牛客多校第7场C--砍树

    题目链接:https://ac.nowcoder.com/acm/contest/887/C?&headNav=acm 题意: 给你 n 种树,有 高度,花费和数量 ,现在问你最少需要花多少钱 ...

  4. 主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间<=k的个数)

    取板粗   好东西来的 1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665 (POJ2104)http://poj.org/probl ...

  5. POJ2761---Feed the dogs (Treap求区间第k大)

    题意 就是求区间第k大,区间 不互相包含. 尝试用treap解决一下 第k大的问题. #include <set> #include <map> #include <cm ...

  6. HDU-1754-I Hate It-线段树-求区间最值和单点修改

    开学新拉的题目,老题重做,思路会稍微比之前清晰,不过这也算是一点点进步了. 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现 ...

  7. [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)

    [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...

  8. BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...

  9. bzoj 3110 [Zjoi2013]K大数查询——线段树套线段树(标记永久化)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 第一道线段树套线段树! 第一道标记永久化! 为什么为什么写了两个半小时啊…… 本想线段 ...

随机推荐

  1. ACM 第十二天

    博弈论(巴什博奕,威佐夫博弈,尼姆博弈,斐波那契博弈,SG函数,SG定理) 一.  巴什博奕(Bash Game): A和B一块报数,每人每次报最少1个,最多报4个,看谁先报到30.这应该是最古老的关 ...

  2. AngularJS 学习笔记--01

    学习 AngularJS 要先了解 MVC 模式 , 即 " 模型--视图--控制器 " . 模型: 包含了需要用到的数据 ; 有两种广义上的模型 : 视图模型 , 只表示从控制器 ...

  3. BZOJ 1263 整数划分(数学+高精度)

    我们不妨考虑可以划分为实数的情况,设划分为x份实数,使得总乘积最大. 易得当每一份都相等时乘积最大.即 ans=(n/x)^x. 现在只需要求出这个函数取得最大值的时候x的取值了. 两边取对数,则有l ...

  4. BZOJ3139/BZOJ1306 HNOI2013比赛/CQOI2009循环赛(搜索)

    搜索好难啊. 1.对于每个分数集合记忆化. 2.某人得分超过总分,剪枝. 3.某人之后全赢也无法达到总分,剪枝. 4.每有一场比赛分出胜负总分会多三分,而平局则会多两分.某人的分出胜负场次或平局场次超 ...

  5. ARC077C pushpush 递推

    ---题面--- 题解: 貌似一般c题都是递推... 观察到最后一个插入的数一定在第一个,倒数第二个插入的数一定在倒数第一个,倒数第三个插入的数一定在第2个,倒数第四个插入的数一定在倒数第2个…… O ...

  6. [TJOI2013]最长上升子序列 平衡树

    其实是一道性质题. 首先观察到插入的数是递增的, 那么根据上升子序列的性质, 我们的非法情况就是统计到了在一个数前面的后插入的数, 但是由于插入的数是递增的,显然插入这个数后,这个数就是最大的,所以除 ...

  7. BZOJ1229 & 洛谷2917:[USACO2008 NOV]toy 玩具 & 洛谷4480:[BJWC2018]餐巾计划问题——题解

    标题很长emmm…… [USACO2008 NOV]toy 玩具 https://www.luogu.org/problemnew/show/P2917 https://www.lydsy.com/J ...

  8. BZOJ2693:JZPTAP——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2693 Description   Input 一个正整数T表示数据组数 接下来T行 每行两个正整数 ...

  9. JavaScript滚动条的制作

    效果演示   这个效果的制作是借助setTimeout的第三个参数.setTimeout/setInterval,这两个函数相信前端开发同学都很熟悉.它们在非IE(6-9)浏览器中还可以如下使用: v ...

  10. 2115: [Wc2011] Xor (线性基+dfs)

    2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 5714  Solved: 2420 题目链接:https://w ...