【BZOJ2006】超级钢琴(主席树,优先队列)

题面

BZOJ

题解

既然是一段区间

首先就要变成单点

所以求一个前缀和

这个时候贪心很明显了:

枚举每一个点和可以和它组成一段的可行的点

全部丢进一个堆里面

取出最大的\(K\)个就行了

但是,很显然,我们做不到都取出来

所以,考虑怎么优化这个过程

每次堆里面对于每个点就先维护一个最大贡献

显然的,只有取出了最大贡献,才会取出次大贡献

那么,最大/次大/\(K\)大贡献怎么算?

一个点,能够和他组成和弦的是一个连续的区间

最大的贡献就是它和区间最小值的差

依次类推

就是区间第\(K\)大

所以搞一棵主席树

维护一下区间第\(K\)大就好啦

再用堆每次取出/加入即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 510000
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Data{int v,id,k;};
bool operator<(Data a,Data b){return a.v<b.v;}
priority_queue<Data> Q;
struct Node
{
int ls,rs;
int sum;
}t[MAX<<6];
int tot,S[MAX],top,rt[MAX],L,R,n,K;
int a[MAX];
void Modify(int &now,int ff,int l,int r,int pos,int w)
{
t[now=++tot]=t[ff];t[now].sum+=w;
if(l==r)return;
int mid=(l+r)>>1;
if(pos<=mid)Modify(t[now].ls,t[ff].ls,l,mid,pos,w);
else Modify(t[now].rs,t[ff].rs,mid+1,r,pos,w);
}
int Query(int A,int B,int l,int r,int K)
{
if(l==r)return l;
int mid=(l+r)>>1;
int sum=t[t[A].ls].sum-t[t[B].ls].sum;
if(sum<K)return Query(t[A].rs,t[B].rs,mid+1,r,K-sum);
else return Query(t[A].ls,t[B].ls,l,mid,K);
}
int main()
{
n=read()+1;K=read();L=read();R=read();
for(int i=2;i<=n;++i)S[++top]=a[i]=a[i-1]+read();S[++top]=0;
sort(&S[1],&S[top+1]);
top=unique(&S[1],&S[top+1])-S-1;
for(int i=1;i<=n;++i)a[i]=lower_bound(&S[1],&S[top+1],a[i])-S;
for(int i=1;i<=n;++i)Modify(rt[i],rt[i-1],1,top,a[i],1);
for(int i=L+1;i<=n;++i)
{
Data x;x.id=i;x.k=1;
x.v=S[a[i]]-S[Query(rt[i-L],rt[max(0,i-R-1)],1,top,1)];
Q.push(x);
}
long long ans=0;
while(K--)
{
Data x=Q.top();Q.pop();
ans+=x.v;
if(x.k==min(x.id-L,R-L+1))continue;
x.k++;
x.v=S[a[x.id]]-S[Query(rt[x.id-L],rt[max(0,x.id-R-1)],1,top,x.k)];
Q.push(x);
}
printf("%lld\n",ans);
return 0;
}

【BZOJ2006】超级钢琴(主席树,优先队列)的更多相关文章

  1. bzoj2006 noi2010 超级钢琴 主席树 + 优先队列

    Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2435  Solved: 1195 Description 小 Z是一个小有名气的钢琴家,最近C博士送 ...

  2. [NOI2010][bzoj2006] 超级钢琴 [主席树/ST表+堆]

    题面: 传送门 思路: 首先容易想到用堆维护的O(n2logn)暴力 那么肯定就是在这个基础上套数据结构了[愉快] 然而我因为过于蒟蒻......只想得到主席树暴力***过去的方法 大概就是把前缀和算 ...

  3. [BZOJ2006] [NOI2010]超级钢琴 主席树+贪心+优先队列

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

  4. [NOI2010]超级钢琴 主席树

    [NOI2010]超级钢琴 链接 luogu 思路 和12省联考的异或粽子一样. 堆维护n个左端点,每次取出来再放回去次 代码 #include <bits/stdc++.h> #defi ...

  5. 【BZOJ 2006】2006: [NOI2010]超级钢琴(RMQ+优先队列)

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2792  Solved: 1388 Description 小 ...

  6. BZOJ 2006 NOI2010 超级钢琴 划分树+堆

    题目大意:给定一个序列.找到k个长度在[l,r]之间的序列.使得和最大 暴力O(n^2logn),肯定过不去 看到这题的第一眼我OTZ了一下午... 后来研究了非常久别人的题解才弄明确怎么回事...蒟 ...

  7. BZOJ2006 超级钢琴

    Description ​ 给定一个长度为n的区间,询问前k大的区间和,区间长度\(\in [L, R]\). $ n, k <= 500000$ Solution ​ 首先求前缀和.把一个区间 ...

  8. 【BZOJ2006】【NOI2010】超级钢琴(主席树,优先队列)

    [BZOJ2006]超级钢琴(主席树,优先队列) 题面 BZOJ 题解 既然是一段区间 首先就要变成单点 所以求一个前缀和 这个时候贪心很明显了: 枚举每一个点和可以和它组成一段的可行的点 全部丢进一 ...

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

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

随机推荐

  1. PLEC-交流电机系统+笔记

    1.固有机械特性近似图 2.三相交流电机的控制系统 1)理论推导 第一次制动选择能耗制动,第二次制动选择倒拉制动. 2)模型搭建 3)模拟仿真 3.心得体会和笔记总结 制动方式的选择主要是根据各个制动 ...

  2. Lua内存分析工具

    最近给公司写了一个lua内存分析工具,可以非常方便的分析出Lua内存泄露问题,有图形化界面操作,方便手机端上传快照等功能 内存分析我是在c语言端写的,也有人写过lua端的分析工具,也蛮好用的,不过lu ...

  3. 原创!!jquery简单tips和dialog

    <!------------------html代码-----------------------> <!DOCTYPE html><html><head&g ...

  4. Yii小部件

    小部件 Yii提供了一套数据小部件widgets,这些小部件可以用于显示数据. DetailView小部件用于显示一条记录数据. ListView和GridView小部件能够用于显示一个拥有分页.排序 ...

  5. Android 如何进行页面传递对象

    当我们从一个页面调到另一个页面的时候,需要把该页面的一些设定值也传递给下一个页面.当要传递的值很多时,我们可以传递一个对象. 页面1: Intent intent = new Intent(PageO ...

  6. web 参考网址

    https://w3c.github.io/ https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket#%E7%A4%BA%E4%BE%8B ...

  7. 避免Toast重复弹出

    Toast.matkText才会创建一个新的实例 private Toast toast = null; private void checkToastResult() { if (toast != ...

  8. HDU - 4496 City 逆向并查集

    思路:逆向并查集,逆向加入每一条边即可.在获取联通块数量的时候,直接判断新加入的边是否合并了两个集合,如果合并了说明联通块会减少一个,否则不变. AC代码 #include <cstdio> ...

  9. Acm弱校奋斗史

    我也是来自弱校的,没有教练,甚至老师都不理我们这种Acmer.看完这篇文章感触颇深. 原文链接 http://acmicpc.info/archives/369 原文 题解:还记得2年前的一个晚上,我 ...

  10. 理解 Git

    Git 如何保存文件 其它版本管理系统通常会保存所有文件及其历次提交的差异(diff / revision),通过 merge 原始文件与各阶段的差异就能获取任何版本的状态 而 Git 保存的是每一次 ...