BZOJ2006 ST表 + 堆
https://www.lydsy.com/JudgeOnline/problem.php?id=2006
题意:在长度N的序列中求K段长度在L到R之间的区间,使得他们的和最大
很容易想到要求一个前缀和。
然后每一个位置i就对应后面的一段i + L - 1 ~ i + R - 1的区间,如果考虑暴力的话,就把每一个值对应的区间内所有的值再全部加入优先队列,取出K个。
看了下数据范围发现不可行。
考虑ST表求最值,在每一个对应区间内找一个最大值,仔细一想也觉得不可行,因为一个区间内的次大值很有可能是会对答案产生贡献的。
事实上我们对ST表加入一点小操作,使得他维护的是静态区间内的最大值下标,rmq(l,r)返回的是l到r区间内最大值的下标p,我们首先将N个三元组i,l,r加入堆,他的贡献是pre[rmq(l,r)] - pre[i - 1],将贡献从大到小排序,当我们处理完一个三元组的时候,再加入分裂开的三元组i,l,p - 1与i,p + 1,r,也就是说,当区间内最大值计算完之后,就往堆中放入一个次大值和次次大值,以此类推即可。
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 5e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,L,R;
int a[maxn];
LL pre[maxn];
const int SP = ;
int Max[maxn][SP];
int mm[maxn];
void initRMQ(int n,LL b[]){
mm[] = -;
for(int i = ; i <= n; i ++){
mm[i] = ((i & (i - )) == )?mm[i - ] + :mm[i - ];
Max[i][] = i;
}
for(int j = ; j <= mm[n]; j ++){
for(int i = ; i + ( << j) - <= n ; i ++){
int x = Max[i][j - ],y = Max[i + ( << (j - ))][j - ];
Max[i][j] = b[x] > b[y]?x:y;
}
}
}
int rmq(int x,int y,LL b[]){
int k = mm[y - x + ];
return b[Max[x][k]] > b[Max[y - ( << k) + ][k]]?Max[x][k]:Max[y - ( << k) + ][k];
}
struct node{
int l,r,o;
node(){}
node(int l,int r,int o):l(l),r(r),o(o){}
LL ans(){
return pre[rmq(l,r,pre)] - pre[o - ];
}
friend bool operator < (node a,node b){
return a.ans() < b.ans();
}
};
int main(){
N = read(); M = read(); L = read(); R = read();
for(int i = ; i <= N ; i ++){
a[i] = read();
pre[i] = pre[i - ] + a[i];
}
initRMQ(N,pre);
priority_queue<node>Q;
for(int i = ; i <= N ; i ++){
if(i + L - > N) break;
Q.push(node(i + L - ,min(i + R - ,N),i));
}
LL ans = ;
while(M--){
node u = Q.top(); Q.pop();
ans += u.ans();
int p = rmq(u.l,u.r,pre);
if(p != u.l) Q.push(node(u.l,p - ,u.o));
if(p != u.r) Q.push(node(p + ,u.r,u.o));
}
Prl(ans);
return ;
}
BZOJ2006 ST表 + 堆的更多相关文章
- BZOJ 2006: [NOI2010]超级钢琴 ST表+堆
开始想到了一个二分+主席树的 $O(n\log^2 n)$ 的做法. 能过,但是太无脑了. 看了一下题解,有一个 ST 表+堆的优美解法. 你发现肯定是选取前 k 大最优. 然后第一次选的话直接选固定 ...
- [BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆)
[BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆) 题面 给出一个长度为n的序列,选k段长度在L到R之间的区间,一个区间的值等于区间内所有元素之的和,使得k个区间的值之和最大.区 ...
- 【BZOJ-2006】超级钢琴 ST表 + 堆 (一类经典问题)
2006: [NOI2010]超级钢琴 Time Limit: 20 Sec Memory Limit: 552 MBSubmit: 2473 Solved: 1211[Submit][Statu ...
- [BZOJ2006][NOI2010]超级钢琴(ST表+堆)
2006: [NOI2010]超级钢琴 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3679 Solved: 1828[Submit][Statu ...
- 【BZOJ2006】[NOI2010]超级钢琴 ST表+堆
[BZOJ2006][NOI2010]超级钢琴 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以 ...
- [NOI2010][bzoj2006] 超级钢琴 [主席树/ST表+堆]
题面: 传送门 思路: 首先容易想到用堆维护的O(n2logn)暴力 那么肯定就是在这个基础上套数据结构了[愉快] 然而我因为过于蒟蒻......只想得到主席树暴力***过去的方法 大概就是把前缀和算 ...
- BZOJ2006:超级钢琴(ST表+堆求前K大区间和)
Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度 ...
- bzoj 2006 [NOI2010]超级钢琴——ST表+堆
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2006 每个右端点的左端点在一个区间内:用堆记录端点位置.可选区间,按价值排序:拿出一个后也许 ...
- BZOJ 2006: [NOI2010]超级钢琴 [ST表+堆 | 主席树]
题意: 一个序列,求k个不相同的长度属于\([L,R]\)的区间使得和最大 前缀和,对于每个r找最小的a[l] 然后我yy了一个可持久化线段树做法...也许会T 实际上主席树就可以了,区间k小值 然后 ...
随机推荐
- ubuntu 14.04zabbix的安装
开始安装 64位 Ubuntu 14.04.5 LTS \n \l 安装zabbix的源,以下操作在root下进行 # wget http://repo.zabbix.com/zabbix/3.0/ ...
- veu——引入iconfont图标
我这里是阿里的iconfont图标,如何下载请看下面这个博文 https://www.cnblogs.com/wangyang0210/articles/9248324.html 创建文件夹 在ass ...
- this view is not constrainted......
this view is not constrainted 解决方案: <EditText android:id="@+id/editText" android:layout ...
- windows 环境下通过运行快速启动程序
在windows环境下,我们可以使用一些系统内置的快捷键来快速启动我们想要的应用程序,我这里举例几个我经常使用的,比如: 快捷键 功能说明 services.msc 查看系统服务 gpedit.ms ...
- 洛谷P3258 松鼠的新家
树上差分 这应该是一道很简单的树上差分了..就是问每个点被覆盖了多少次. 要注意我们最后dfs后,要把除第一个节点以外的所有点的-1,因为有些点作为起点和终点覆盖了两次,按照题目意思是不用覆盖两次的. ...
- python+appium里的等待时间
为什么要用等待时间: 今天在写App的自动化的脚本时发现一个元素,时而能点击,时而又不能点击到,很是心塞,原因是:因为元素还没有被加载出来,查找的代码就已经被执行了,自然就找不到元素了.解决方式:可以 ...
- 【XSY2787】Mythological VII 贪心
题目描述 有两个指针\(l,r\),初始时\(l=r=k\) 给你\(a_1,\ldots,a_n\),你要移动\(l,r\),\(l\)只能每次向左移一个数,\(r\)只能向右移一个数,要求任意时刻 ...
- 【BZOJ4872】【SHOI2017】分手是祝愿 期望DP
题目大意 有\(n\)盏灯和\(n\)个开关,初始时有的灯是亮的,有的灯是暗的.按下第\(i\)个开关会使第\(j\)盏灯的状态被改变,其中\(j|i\).每次你会随机操作一个开关,直到可以通过不多于 ...
- Gym - 101848C Object-Oriented Programming (树链剖分+线段树+动态开点)
C. Object-Oriented Programming time limit per test 3.0 s memory limit per test 1024 MB input standar ...
- 爬虫_微信小程序社区教程(crawlspider)
照着敲了一遍,,, 需要使用"LinkExtrator"和"Rule",这两个东西决定爬虫的走向. 1.allow设置规则的方法:要能够限制在我们想要的url上 ...