题面:

传送门

思路:

首先容易想到用堆维护的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. Window_Bat_Scripts—检测特定网段未使用的IP地址

    1.1    脚本名称 Check_IP_Not_Use.bat 1.2    脚本代码 @Echo off set /p input_number=请输入网络位(192.168.1.): IF EX ...

  2. 单片机入门学习笔记5:STC下载器

    STC下载器主要集成了, 1.芯片识别,下载/编程 2.端口识别 3.串口助手 4.KEIL仿真设置 5.芯片选型 6.范例程序 (集成了定时器,串口等例程) 7.波特率计算器 8.定时器计算器 9. ...

  3. c++ vector实例

    #include <iostream> #include <string> #include <vector> #include <iostream> ...

  4. 安装ANSYS19.0的正确方法(附下载)

    安装ANSYS19.0的正确方法 卸载干净旧版本ANSYS 安装或重新安装之前必须先卸载干净,安装过旧版本ANSYS的也要确保卸载干净.电脑环境准备参考以下内容 ANSYS 卸载后重装需要注意的问题_ ...

  5. Gym - 101981D Country Meow(模拟退火)

    题意 三维空间有\(n\)个点,找到另外一个点,离所有点的最大距离最小.求这个距离. 题解 \(1\).最小球覆盖,要找的点为球心. \(2\).模拟退火. 还是补一下模拟退火的介绍吧. 模拟退火有一 ...

  6. callback回调函数【转】

    请给作者点赞--> 原文链接 什么是回调函数? 我们绕点远路来回答这个问题. 编程分为两类:系统编程(system programming)和应用编程(application programmi ...

  7. 第三模块 面向对象& 网络编程基础 实战考核

    1.简述构造方法和析构方法. 构造方法(__init__):主要作用是实例化时给实例一些初始化参数,或执行一些其它的初始化工作,总之因为这个__init__只要一实例化, 就会自动执行,不管你在这个方 ...

  8. cf965e Short Code

    ref #include <algorithm> #include <iostream> #include <cstring> #include <cstdi ...

  9. Python框架之Django学习笔记(六)

    模板 上篇博文学习了动态视图,但是,视图中返回文本的方式有点特别. 也就是说,HTML被直接硬编码在 Python 代码之中. def current_datetime(request): now = ...

  10. leetcode 【 Two Sum 】python 实现

    题目: Given an array of integers, find two numbers such that they add up to a specific target number. ...