题面:

传送门

思路:

首先容易想到用堆维护的O(n2logn)暴力

那么肯定就是在这个基础上套数据结构了【愉快】

然而我因为过于蒟蒻......只想得到主席树暴力***过去的方法

大概就是把前缀和算出来,然后放到一棵线段树里面

对于每一个i(i=1...(n-L+1)),线段树查询以i为左端点的所有区间右端点中,前缀和最大的一个

因为区间[i,j]可以变成pre[j]-pre[i]的形式,那么只需要最大化pre[j]就可以了

一开始,对于所有的i把这个最大值求出来,减掉pre[i-1],再放到堆里面

每次从堆顶取出当前最大值,然后答案加上这个值,同时主席树上修改一波,把这个点在树上的值改成-inf

其实一共有n棵主席树,只不过每一棵都公用同一个初始树,后面每次修改又只会新开logn的节点,所以总空间复杂度应该是O(nlogn+klogn)的

就这样,总时间复杂度O(nlogn+klogn),常数略大

然而,菊苣们早已开发出了新的希望算法,那就是查询O(1)的ST表

把上文中的初始询问(n个,在初始线段树上的那些)转化成三元组(i,L,R),代表左端点是i的,长度在[L,R]之内的序列最大值

那么,每次堆顶弹出以后,可以这样操作:

设堆顶元素为x,我们新建两个三元组(i,L,x-1)(i,x+1,R),把这两个三元组的值求出来放到堆里面去即可

效率虽然还是O(nlogn+klogn),但是常数比我的算法不知道高到哪里去了,跑的贼快

Code:

不知道为什么,500000的点需要开两千五百万的数组......连续3次RE

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 1e15
#define ll long long
using namespace std;
inline int read(){
int re=,flag=;char ch=getchar();
while(ch>''||ch<''){
if(ch=='-') flag=-;
ch=getchar();
}
while(ch>=''&&ch<='') re=(re<<)+(re<<)+ch-'',ch=getchar();
return re*flag;
}
struct node{
ll w;int pos;
bool operator <(const node &b){
return w<b.w;
}
}a[];
struct NODE{
ll w;int pos1,pos2;
bool operator <(const NODE &b)const{
return w<b.w;
}
};
int n,m,L,R,x[];
int ch[][],cnt,root[];ll pre[];
priority_queue<NODE>q;
void update(int x){
if(a[ch[x][]].w>=a[ch[x][]].w) a[x].w=a[ch[x][]].w,a[x].pos=a[ch[x][]].pos;
else a[x].w=a[ch[x][]].w,a[x].pos=a[ch[x][]].pos;
}
int build(int l,int r){
int mid=(l+r)>>,cur=++cnt;
if(l==r){
a[cur].w=pre[l];a[cur].pos=l;return cur;
}
ch[cur][]=build(l,mid);ch[cur][]=build(mid+,r);
update(cur);
return cur;
}
node max(node l,node r){
return l<r?r:l;
}
node query(int l,int r,int ql,int qr,int cur){
int mid=(l+r)>>;node re=(node){-inf,};
if(l>=ql&&r<=qr) return a[cur];
if(mid>=ql) re=max(re,query(l,mid,ql,qr,ch[cur][]));
if(mid<qr) re=max(re,query(mid+,r,ql,qr,ch[cur][]));
return re;
}
int change(int l,int r,int u,int his){
int mid=(l+r)>>,cur=++cnt;
if(l==r){
a[cur]=(node){-inf,l};return cur;
}
if(u<=mid) ch[cur][]=ch[his][],ch[cur][]=change(l,mid,u,ch[his][]);
else ch[cur][]=ch[his][],ch[cur][]=change(mid+,r,u,ch[his][]);
update(cur);return cur;
}
int main(){
freopen("piano.in","r",stdin);
freopen("piano.out","w",stdout);
int i,t1;ll ans=;node tmp;NODE tt;
n=read();m=read();L=read();R=read();
for(i=;i<=n;i++) x[i]=read(),pre[i]=pre[i-]+(ll)x[i];
t1=build(,n);
for(i=;i<=n-L+;i++){
root[i]=t1;tmp=query(,n,min(n,i+L-),min(n,i+R-),t1);
q.push((NODE){-pre[i-]+tmp.w,i,tmp.pos});
}
for(i=;i<=m;i++){
ans+=q.top().w;tt=q.top();q.pop();
root[tt.pos1]=change(,n,tt.pos2,root[tt.pos1]);
tmp=query(,n,min(n,tt.pos1+L-),min(n,tt.pos1+R-),root[tt.pos1]);
q.push((NODE){-pre[tt.pos1-]+tmp.w,tt.pos1,tmp.pos});
}
printf("%lld\n",ans);
}

[NOI2010][bzoj2006] 超级钢琴 [主席树/ST表+堆]的更多相关文章

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

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

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

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

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

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

  4. BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)

    题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...

  5. [HEOI2016] 字符串 - 后缀数组,主席树,ST表,二分

    [HEOI2016] 字符串 Description 给定一个字符串 \(S\), 有 \(m\) 个询问,每个询问给定参数 \((a,b,c,d)\) ,求 \(s[a..b]\) 的子串与 \(s ...

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

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

  7. [BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆)

    [BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆) 题面 给出一个长度为n的序列,选k段长度在L到R之间的区间,一个区间的值等于区间内所有元素之的和,使得k个区间的值之和最大.区 ...

  8. 题解 【NOI2010】超级钢琴

    [NOI2010]超级钢琴 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号 ...

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

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

随机推荐

  1. 【转】iOS开发4:关闭键盘

    在 iOS 程序中当想要在文本框中输入数据,轻触文本框会打开键盘.对于 iPad 程序,其键盘有一个按钮可以用来关闭键盘,但是 iPhone 程序中的键盘却没有这样的按钮,不过我们可以采取一些方法关闭 ...

  2. frombuffer的用法

    函数原型为:numpy.ma.frombuffer(buffer, dtype=float, count=-1, offset=0) import numpy s = 'hello world' pr ...

  3. CUDA直方图实例=CPU+GPU(global)+GPU(shared)

    项目打包下载链接 顺便批判下CSDN上传坑爹现象,好多次都是到了95%或者99%就不动了.我……

  4. 【Java-JVM】定量分析解决OutOfMemoryError: PermGen space, 来看科学量化分析

    网络上搜集,有操作有分析. 一.问题 在部署大型的 Java Web项目的时候,或者在 MyEclipse 中进行调试的时候经常出现: OutOfMemoryError: PermGen space ...

  5. c++question 005 c++中转义字符有哪些?

    (1)'\a'  注意,这里不再是两个字符\ 和 a 而是表达了一个具体的含义是,蜂鸣一声 (2)'\n' 换行,这里不再是两个字符\ 和 n 而是表达了一个具体的含义是,相当于 endl (3)'\ ...

  6. antd-design-pro 服务代理问题

    公司希望又一个后台管理页面.因为之前技术栈是react 所以选择了antd-design-pro作为后台的框架. 在连调api的时候,困惑怎么去代理.因为网上查到很多都是1.0的版本,而我现在用的是2 ...

  7. jsp 生成验证码代码

    调用方法:在jsp页面用图像标签便可以直接调用如下是标签代码<img border=0 src="image.jsp">,只需要把该代码发在验证码要显示的区域就可以了) ...

  8. 记python版本管理--pyenv

    随记: 众所周知,python2.x版本与3.x版本有比较大的区别,如果你是2.x版本的使用者,突然接了3.x版本的项目,或者反过来,遇到这种情况该怎么办呢?重新安装自己电脑上的python,来匹配对 ...

  9. ls显示前几行或后几行数据

    显示前3行数据 ls -l|head -n 3 显示后3行数据 ls -l|tail -n 3

  10. 一道JS面试题所引发的"血案",透过现象寻本质,再从本质看现象

    觉得本人写的不算很烂的话,可以登录关注一下我的GitHub博客,新手写东西写的不好之处,还望见谅,毕竟水平有限,写东西只为交流提高,一起学习,还望大神多加指点,指出纰漏,和提出宝贵的意见,博客会坚持写 ...