题面:

传送门

思路:

首先容易想到用堆维护的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. c++连接mysql并提示“无法解析的外部符号 _mysql_server_init@12”解决方法&提示缺少“libmysql.dll”

    课程作业要用c++连接mysql server,但是出现些小问题,经查阅资料已经解决,做一下笔记. 环境:vs2017, mysql版本是8.0.16-winx64. 设置项目属性   项目 -  C ...

  2. 项目:Vue+node+后台管理项目小结

    序:本文主要分两块说:项目机制,具体用到的知识块. 1. 项目机制 项目的原型以vue-cli为原型,进行项目的初步构建.项目以node.js服务和webpack打包机制为依托,将.vue文件打包为浏 ...

  3. shell脚本,awk实现跳过文件里面的空行。

    1.用awk '{if(!NF ){next}}1' file11 实现对文件里面的空行进行跳过操作,并输出结果. 2. awk '{if(!NF || /^#/){next}}1' file11 实 ...

  4. 垂直居中一个img

    { display:table-cell; text-align:center; vertical-align:middle; }

  5. php 多维数组指定某个值作为键

    $temp_key = array_column($mobile_arr,'cidf'); //键值 $mobile_arr = array_combine($temp_key,$mobile_arr ...

  6. Scrapy框架中选择器的用法【转】

    Python爬虫从入门到放弃(十四)之 Scrapy框架中选择器的用法 请给作者点赞 --> 原文链接 Scrapy提取数据有自己的一套机制,被称作选择器(selectors),通过特定的Xpa ...

  7. GSMM数据库设计小结

    边写边结 1.新增,删除,修改在各自的DAL中进行,查,可以新建一个DAL,里面是需要的各个属性,跨表,不同表属性整合成一个对象(集合)返回,输出到用户界面.

  8. (ADO.NET小知识点汇总)看到什么记什么

    1.数据库连接池:在同时连接数不多的情况下, 打开一个链接往数据库导1W条数据的耗时 跟 导一条数据就打开跟关闭数据库连接的耗时 两者其实相差不大,这是为什么呢?打开关闭的本身不是有很多耗时吗?这是因 ...

  9. 配置Spring.NET

    先引入关键的程序集 Common.Logging.dll Spring.Core.dll 在配置文件配置中: <configSections> ...... <sectionGrou ...

  10. 3 View - Response对象

    1. HttpResponse对象:返回数据 from django.http import HttpResponse 在django.http模块中定义了HttpResponse对象的API Htt ...