题面:

传送门

思路:

首先容易想到用堆维护的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. 用TreeView控件遍历磁盘目录

    实现效果: 知识运用: ListView控件中Items集合的Add方法  TteeView控件中Nodes集合的Add方法 实现代码: private void Form1_Load(object ...

  2. Sql中的if函数学习

    今天,在修改项目bug时遇到一些需要计算的功能实现,虽然可以用java代码写,但是由于时间较为充裕,有尝试用sql写一下,学习到了if函数 , o.containerSendNet),) transi ...

  3. Java面向对象之继承,方法重写,super关键字,员工类系列继承题

    在程序中,如果想声明一个类继承另一个类,需要使用extends关键字. 格式: class 子类 extends 父类 {} 继承的好处 1.继承的出现提高了代码的复用性,提高软件开发效率. 2.继承 ...

  4. css3 横向拖拽

    css: .tab{         list-style-type: none;         display:-webkit-box;         display:-webkit-flex; ...

  5. CodeForces 651B

    #include <cstdio> #include <algorithm> using namespace std; int a[1005], n, temp, maxk; ...

  6. sed速查手册

    1. Sed简介sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后, ...

  7. 2015-2016 Northwestern European Regional Contest (NWERC 2015)

    训练时间:2019-04-05 一场读错三个题,队友恨不得手刃了我这个坑B. A I J 简单,不写了. C - Cleaning Pipes (Gym - 101485C) 对于有公共点的管道建边, ...

  8. bzoj2733: [HNOI2012]永无乡(splay)

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3778  Solved: 2020 Description 永 ...

  9. LINUX下实现按秒执行计划任务

    由于linux最小单位为分,但是很多需求上需要按秒执行,如30秒请求一个URL地址之类的,思路很简单就是修改计划任务脚本用循环控制,代码如下: #!/bin/bash PATH=/bin:/sbin: ...

  10. GBDT算法简述

    提升决策树GBDT 梯度提升决策树算法是近年来被提及较多的一个算法,这主要得益于其算法的性能,以及该算法在各类数据挖掘以及机器学习比赛中的卓越表现,有很多人对GBDT算法进行了开源代码的开发,比较火的 ...