题面:BZOJ传送门 洛谷传送门

让你求前$K$大的子序列和,$n\leq 5*10^{5}$

只想到了个$nlog^{2}n$的做法,似乎要被卡常就看题解了..

好神奇的操作啊,我傻了

我们把序列和拆成两个前缀和相减

对于一个左端点$x$,它可以取的范围是$[x+l,x+r]$,查出该范围内的第1大值,然后把左端点编号$x$,取的是第几大值$k$,以及答案这些信息封成结构体推进堆里

根据贪心的策略我们要取最大的,要维护一个关于答案的大根堆

每次都取出堆顶元素,在$x$对应范围内查找第$k+1$大值,再把信息重新推回堆里,如此重复K次即可

上述过程也可以用区间RMQ实现,结构体里记录能取的左右端点就行了,每次取堆顶元素以后都拆成两部分推回堆里,似乎RMQ的做法空间常数会小不少

  1. #include <queue>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define N1 500010
  6. #define M1 N1*30
  7. #define ll long long
  8. using namespace std;
  9.  
  10. template <typename _T> void read(_T &ret)
  11. {
  12. ret=; _T fh=; char c=getchar();
  13. while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
  14. while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
  15. ret=ret*fh;
  16. }
  17.  
  18. struct SEG{
  19. int ls[M1],rs[M1],sz[M1],root[N1],tot;
  20. inline void pushup(int rt)
  21. {
  22. sz[rt]=sz[ls[rt]]+sz[rs[rt]];
  23. }
  24. void update(int x,int l,int r,int rt1,int &rt2,int w)
  25. {
  26. if(!rt2||rt2==rt1){ rt2=++tot; ls[rt2]=ls[rt1]; rs[rt2]=rs[rt1]; sz[rt2]=sz[rt1]; }
  27. if(l==r){ sz[rt2]+=w; return; }
  28. int mid=(l+r)>>;
  29. if(x<=mid) update(x,l,mid,ls[rt1],ls[rt2],w);
  30. else update(x,mid+,r,rs[rt1],rs[rt2],w);
  31. pushup(rt2);
  32. }
  33. int find(int K,int l,int r,int rt1,int rt2)
  34. {
  35. if(l==r) return l;
  36. int mid=(l+r)>>;
  37. if(K<=sz[rs[rt2]]-sz[rs[rt1]]) return find(K,mid+,r,rs[rt1],rs[rt2]);
  38. else return find(K-sz[rs[rt2]]+sz[rs[rt1]],l,mid,ls[rt1],ls[rt2]);
  39. }
  40. }s;
  41.  
  42. int n,nn,K,L,R;
  43. int a[N1],b[N1]; ll sa[N1],t[N1];
  44. struct node{
  45. int x,K;ll val;
  46. node(int x,int K,ll val):x(x),K(K),val(val){} node(){}
  47. friend bool operator < (const node &s1,const node &s2)
  48. {
  49. if(s1.val!=s2.val) return s1.val<s2.val;
  50. if(s1.x!=s2.x) return s1.x<s2.x;
  51. return s1.K<s2.K;
  52. }
  53. };
  54. priority_queue<node>q;
  55.  
  56. int main()
  57. {
  58. scanf("%d%d%d%d",&n,&K,&L,&R);
  59. int i,j,l,r,x,y,k; t[]=;
  60. for(i=;i<=n;i++) read(a[i]), sa[i]=sa[i-]+a[i], t[i+]=sa[i];
  61. sort(t+,t+n+); nn=unique(t+,t+n+)-(t+);
  62. for(i=;i<=n;i++)
  63. {
  64. b[i]=lower_bound(t+,t+nn+,sa[i])-t;
  65. s.update(b[i],,nn,s.root[i-],s.root[i],);
  66. }
  67. node p;
  68. for(i=;i<n;i++)
  69. {
  70. l=i+L; if(l>n) continue; r=min(i+R,n);
  71. x=s.find(,,nn,s.root[l-],s.root[r]);
  72. q.push(node(i,,t[x]-sa[i]));
  73. }
  74. ll ans=;
  75. while(K--)
  76. {
  77. p=q.top(); q.pop(); ans+=p.val;
  78. i=p.x, l=i+L, r=min(i+R,n); if(p.K==r-l+) continue;
  79. x=s.find(p.K+,,nn,s.root[l-],s.root[r]);
  80. q.push(node(i,p.K+,t[x]-sa[i]));
  81. }
  82. printf("%lld\n",ans);
  83. return ;
  84. }

BZOJ 2006 [NOI2010]超级钢琴 (堆+主席树)的更多相关文章

  1. Bzoj 2006: [NOI2010]超级钢琴 堆,ST表

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2222  Solved: 1082[Submit][Statu ...

  2. BZOJ2006[NOI2010]超级钢琴——堆+主席树

    题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中 ...

  3. BZOJ 2006: [NOI2010]超级钢琴( RMQ + 堆 )

    取最大的K个, 用堆和RMQ来加速... ----------------------------------------------------------------- #include<c ...

  4. BZOJ 2006: [NOI2010]超级钢琴

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2613  Solved: 1297[Submit][Statu ...

  5. BZOJ 2006: [NOI2010]超级钢琴 [ST表+堆 | 主席树]

    题意: 一个序列,求k个不相同的长度属于\([L,R]\)的区间使得和最大 前缀和,对于每个r找最小的a[l] 然后我yy了一个可持久化线段树做法...也许会T 实际上主席树就可以了,区间k小值 然后 ...

  6. BZOJ 2006 超级钢琴(堆+主席树)

    很好的一道题. 题意:给出长度为n的数列,选择k个互不相同的区间,满足每个区间长度在[L,R]内,求所有选择的区间和的总和最大是多少.(n,k<=5e5). 首先将区间和转化为前缀和之差,那么我 ...

  7. BZOJ 2006: [NOI2010]超级钢琴 ST表+堆

    开始想到了一个二分+主席树的 $O(n\log^2 n)$ 的做法. 能过,但是太无脑了. 看了一下题解,有一个 ST 表+堆的优美解法. 你发现肯定是选取前 k 大最优. 然后第一次选的话直接选固定 ...

  8. 洛谷 P2048 BZOJ 2006 [NOI2010]超级钢琴

    题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中A ...

  9. luogu2048 [NOI2010]超级钢琴 (优先队列+主席树)

    思路:先扫一遍所有点作为右端点的情况,把它们能产生的最大值加到一个优先队列里,然后每次从优先队列里取出最大值,再把它对应的区间的次大值加到优先队列里,这样做K次 可以用一个前缀和,每次找i为右端点的第 ...

随机推荐

  1. but no declaration can be found for element &#39;aop:aspectj-autoproxy&#39;.

    1.错误描写叙述 Multiple annotations found at this line: - cvc-complex-type.2.4.c: The matching wildcard is ...

  2. LINQ体验(2)——C# 3.0新语言特性和改进(上篇)

    整体来说.Visual Studio 2008和.NET 3.5是建立在.NET2.0核心的基础之上,.NET2.0核心本身将不再变化(假设不了解.NET2.0的朋友,请參看MSDN或者一些经典的书籍 ...

  3. 基于Windows Azure 搭建基于SharePoint 2010 Intranet、Extranet、Internet (4): 配置传出邮件服务: 使用 outlook.com 发送邮件通知

    前几篇文章,已经安装了SharePoint 2010,今天将演示如何配置传出邮件.由于某些原因,企业可能没有安装自己邮件服务器,此时我们可以使用公共的邮箱服务来发送邮件通知,比如outlook.com ...

  4. Android 系统开机logo的修改【转】

    本文转载自:http://blog.csdn.net/yandongqiangZHRJ/article/details/8585273 看到了好几个修改logo的博文,但是说的不是很清楚,在这里亲手送 ...

  5. 欧拉函数&&欧拉定理

    定义和简单性质 欧拉函数在OI中是个非常重要的东西,不知道的话会吃大亏的. 欧拉函数用希腊字母φ表示,φ(N)表示N的欧拉函数. 对φ(N)的值,我们可以通俗地理解为小于N且与N互质的数的个数(包含1 ...

  6. bzoj 1800 & 洛谷 P2165 [AHOI2009]飞行棋 —— 模拟

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1800   https://www.luogu.org/problemnew/show/P21 ...

  7. bzoj 3598 [ Scoi 2014 ] 方伯伯的商场之旅 ——数位DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3598 数位DP...东看西看:http://www.cnblogs.com/Artanis/ ...

  8. 排序系列 之 堆排序算法 —— Java实现

       基本概念: 二叉堆是完全二叉树或者是近似完全二叉树. 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆. 一般将二叉堆简称 ...

  9. The Moronic Cowmpouter(负进位制转换)

    http://poj.org/problem?id=3191 题意:将一个整型的十进制整数转化为-2进制整数. #include <stdio.h> #include <algori ...

  10. 工具分享2:Python 3.6.4、文本编辑器EditPlus、文本编辑器Geany

    工具官网下载地址: https://www.python.org/downloads/ python 3.6.0下载链接: 链接:https://pan.baidu.com/s/1snuSxsx 密码 ...