BZOJ 2006 [NOI2010]超级钢琴 (堆+主席树)
让你求前$K$大的子序列和,$n\leq 5*10^{5}$
只想到了个$nlog^{2}n$的做法,似乎要被卡常就看题解了..
好神奇的操作啊,我傻了
我们把序列和拆成两个前缀和相减
对于一个左端点$x$,它可以取的范围是$[x+l,x+r]$,查出该范围内的第1大值,然后把左端点编号$x$,取的是第几大值$k$,以及答案这些信息封成结构体推进堆里
根据贪心的策略我们要取最大的,要维护一个关于答案的大根堆
每次都取出堆顶元素,在$x$对应范围内查找第$k+1$大值,再把信息重新推回堆里,如此重复K次即可
上述过程也可以用区间RMQ实现,结构体里记录能取的左右端点就行了,每次取堆顶元素以后都拆成两部分推回堆里,似乎RMQ的做法空间常数会小不少
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 500010
#define M1 N1*30
#define ll long long
using namespace std; template <typename _T> void read(_T &ret)
{
ret=; _T fh=; char c=getchar();
while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
ret=ret*fh;
} struct SEG{
int ls[M1],rs[M1],sz[M1],root[N1],tot;
inline void pushup(int rt)
{
sz[rt]=sz[ls[rt]]+sz[rs[rt]];
}
void update(int x,int l,int r,int rt1,int &rt2,int w)
{
if(!rt2||rt2==rt1){ rt2=++tot; ls[rt2]=ls[rt1]; rs[rt2]=rs[rt1]; sz[rt2]=sz[rt1]; }
if(l==r){ sz[rt2]+=w; return; }
int mid=(l+r)>>;
if(x<=mid) update(x,l,mid,ls[rt1],ls[rt2],w);
else update(x,mid+,r,rs[rt1],rs[rt2],w);
pushup(rt2);
}
int find(int K,int l,int r,int rt1,int rt2)
{
if(l==r) return l;
int mid=(l+r)>>;
if(K<=sz[rs[rt2]]-sz[rs[rt1]]) return find(K,mid+,r,rs[rt1],rs[rt2]);
else return find(K-sz[rs[rt2]]+sz[rs[rt1]],l,mid,ls[rt1],ls[rt2]);
}
}s; int n,nn,K,L,R;
int a[N1],b[N1]; ll sa[N1],t[N1];
struct node{
int x,K;ll val;
node(int x,int K,ll val):x(x),K(K),val(val){} node(){}
friend bool operator < (const node &s1,const node &s2)
{
if(s1.val!=s2.val) return s1.val<s2.val;
if(s1.x!=s2.x) return s1.x<s2.x;
return s1.K<s2.K;
}
};
priority_queue<node>q; int main()
{
scanf("%d%d%d%d",&n,&K,&L,&R);
int i,j,l,r,x,y,k; t[]=;
for(i=;i<=n;i++) read(a[i]), sa[i]=sa[i-]+a[i], t[i+]=sa[i];
sort(t+,t+n+); nn=unique(t+,t+n+)-(t+);
for(i=;i<=n;i++)
{
b[i]=lower_bound(t+,t+nn+,sa[i])-t;
s.update(b[i],,nn,s.root[i-],s.root[i],);
}
node p;
for(i=;i<n;i++)
{
l=i+L; if(l>n) continue; r=min(i+R,n);
x=s.find(,,nn,s.root[l-],s.root[r]);
q.push(node(i,,t[x]-sa[i]));
}
ll ans=;
while(K--)
{
p=q.top(); q.pop(); ans+=p.val;
i=p.x, l=i+L, r=min(i+R,n); if(p.K==r-l+) continue;
x=s.find(p.K+,,nn,s.root[l-],s.root[r]);
q.push(node(i,p.K+,t[x]-sa[i]));
}
printf("%lld\n",ans);
return ;
}
BZOJ 2006 [NOI2010]超级钢琴 (堆+主席树)的更多相关文章
- Bzoj 2006: [NOI2010]超级钢琴 堆,ST表
2006: [NOI2010]超级钢琴 Time Limit: 20 Sec Memory Limit: 552 MBSubmit: 2222 Solved: 1082[Submit][Statu ...
- BZOJ2006[NOI2010]超级钢琴——堆+主席树
题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中 ...
- BZOJ 2006: [NOI2010]超级钢琴( RMQ + 堆 )
取最大的K个, 用堆和RMQ来加速... ----------------------------------------------------------------- #include<c ...
- BZOJ 2006: [NOI2010]超级钢琴
2006: [NOI2010]超级钢琴 Time Limit: 20 Sec Memory Limit: 552 MBSubmit: 2613 Solved: 1297[Submit][Statu ...
- BZOJ 2006: [NOI2010]超级钢琴 [ST表+堆 | 主席树]
题意: 一个序列,求k个不相同的长度属于\([L,R]\)的区间使得和最大 前缀和,对于每个r找最小的a[l] 然后我yy了一个可持久化线段树做法...也许会T 实际上主席树就可以了,区间k小值 然后 ...
- BZOJ 2006 超级钢琴(堆+主席树)
很好的一道题. 题意:给出长度为n的数列,选择k个互不相同的区间,满足每个区间长度在[L,R]内,求所有选择的区间和的总和最大是多少.(n,k<=5e5). 首先将区间和转化为前缀和之差,那么我 ...
- BZOJ 2006: [NOI2010]超级钢琴 ST表+堆
开始想到了一个二分+主席树的 $O(n\log^2 n)$ 的做法. 能过,但是太无脑了. 看了一下题解,有一个 ST 表+堆的优美解法. 你发现肯定是选取前 k 大最优. 然后第一次选的话直接选固定 ...
- 洛谷 P2048 BZOJ 2006 [NOI2010]超级钢琴
题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中A ...
- luogu2048 [NOI2010]超级钢琴 (优先队列+主席树)
思路:先扫一遍所有点作为右端点的情况,把它们能产生的最大值加到一个优先队列里,然后每次从优先队列里取出最大值,再把它对应的区间的次大值加到优先队列里,这样做K次 可以用一个前缀和,每次找i为右端点的第 ...
随机推荐
- ORACLE11G 将dataguard的rman备份恢复到測试环境的单机oracle中的具体过程
. 也就是说此时数据库仅仅能进行不全然恢复了,在打开数据库时得使用resetlogs打开. recover database until scn 11412370952; RMAN> recov ...
- swift2.0学习之拓展
拓展:和oc的拓展方法功能差点儿相同.就是给已经存在的类,结构体.枚举,协议类型添加新的方法 拓展语法: 用extensionkeyword声明: extension SomeType { // ne ...
- GTK经常使用控件之行编辑( GtkEntry )
行编辑,仅仅同意输入一行内容的控件.如password输入框. 行编辑的创建: GtkWidget *gtk_entry_new(void); 返回值:行编辑指针 设置行编辑内容的最大长度: void ...
- ICM Technex 2017 and Codeforces Round #400 (Div. 1 + Div. 2, combined) C. Molly's Chemicals
感觉自己做有关区间的题目方面的思维异常的差...有时简单题都搞半天还完全没思路,,然后别人提示下立马就明白了...=_= 题意:给一个含有n个元素的数组和k,问存在多少个区间的和值为k的次方数. 题解 ...
- 学习笔记—— 一些UPDATE语句
UPDATE语句原来还有许多种写法,有的还很复杂,孤陋寡闻的我甚至闻所未闻.幸甚至哉,记而志之. 0.UPDATE 表名 SET 字段... FROM ...的方式 USE AdventureWork ...
- hdu 1695(莫比乌斯反演)
GCD Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- category中添加属性的简单方式
一.概念扩充: 1.如我们所知,使用category是用来对现有类进行功能扩展,或者将类分成多模块的一种方式.由声明和实现两部分组成.可以单独写成Objiective-C File类型文件(包含.h和 ...
- python 函数参数的传递(参数带星号的说明)
python中函数参数的传递是通过赋值来传递的.函数参数的使用又有俩个方面值得注意:1.函数参数是如何定义的 2.在调用函数的过程中参数是如何被解析 先看第一个问题,在python中函数参数的定义主要 ...
- 最短路( spfa)
最短路 http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2622 #include <std ...
- 前端面试:问到GET和POST两种区别
最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. "标准答案"(本标准答案参考自w3schools): GET在浏览器回退时是无害的,而P ...