BZOJ2006 超级钢琴
Description
给定一个长度为n的区间,询问前k大的区间和,区间长度\(\in [L, R]\)。 $ n, k <= 500000$
Solution
首先求前缀和。把一个区间拆成两个前缀和之差。
对于一个固定的右端点。我们首先需要最小化左端点。那么我们就在题目条件允许的范围内先求出左端点最小的位置, 但是一个区间的次大值可能超过别的区间的最大值, 这很麻烦。
开一个堆, 维护一个三元组(Pos, Kth, Val), 表示以Pos为右端点,本次查到区间第Kth大,值为Val。
然后把一个区间从堆中取出来时, 就把他的(Pos, Kth + 1, Val_)加入堆。
然后只要取k次即可。
时间复杂度\(O((n + k)log_{2}^{n})\)
反思
刚刚开始想到把每个右端点的左端点按照大小都加进小根堆, 小根堆大小为K,如果超过就弹出一个。 如果当前值小于堆顶就break, 然后就被卡T到8s
最后发现,其实你并不需要把全部的都加入堆,因为只要当前的区间被弹出,才有可能用他的次大值。
所以我们只要贪心取最大值就可以的。
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define Debug(s) debug("The massage in line %d, Function %s: %s\n", __LINE__, __FUNCTION__, s)
typedef long long LL;
typedef long double LD;
const int BUF_SIZE = (int)1e6 + 10;
struct fastIO {
char buf[BUF_SIZE], buf1[BUF_SIZE];
int cur, cur1;
FILE *in, *out;
fastIO() {
cur = BUF_SIZE, in = stdin, out = stdout;
cur1 = 0;
}
inline char getchar() {
if(cur == BUF_SIZE) fread(buf, BUF_SIZE, 1, in), cur = 0;
return *(buf + (cur++));
}
inline void putchar(char ch) {
*(buf1 + (cur1++)) = ch;
if (cur1 == BUF_SIZE) fwrite(buf1, BUF_SIZE, 1, out), cur1 = 0;
}
inline int flush() {
if (cur1 > 0) fwrite(buf1, cur1, 1, out);
return cur1 = 0;
}
}IO;
#define getchar IO.getchar
#define putchar IO.putchar
int read() {
char ch = getchar();
int x = 0, flag = 1;
for(;!isdigit(ch); ch = getchar()) if(ch == '-') flag *= -1;
for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
return x * flag;
}
void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar(x % 10 + 48);
}
void putString(char s[], char EndChar = '\n') {
rep(i, 0, strlen(s) - 1) putchar(*(s + i));
if(~EndChar) putchar(EndChar);
}
#define Maxn 500009
int n, k, L, R, a[Maxn];
LL s[Maxn];
template <typename T, int (*Cmp)(T a, T b)> struct Heap {
T a[Maxn];
int len;
void push(T val) {
a[++len] = val;
push_heap(a + 1, a + len + 1, Cmp);
}
T pop() { pop_heap(a + 1, a + len + 1, Cmp); return a[len--];}
T top() {return a[1];}
T empty() { return !len;}
};
LL W[Maxn], d, Ns[Maxn];
namespace Chairman {
int t[Maxn * 64], lc[Maxn * 64], rc[Maxn * 64], amt, rt[Maxn];
int build(int l, int r) {
int u = ++amt, mid = (l + r) >> 1;
if(l == r) return u;
lc[u] = build(l, mid);
rc[u] = build(mid + 1, r);
return u;
}
int modify(int rt, int l, int r, int pos) {
int mid = (l + r) >> 1, u = ++amt;
t[u] = t[rt] + 1; lc[u] = lc[rt], rc[u] = rc[rt];
if(l == r) return u;
(pos <= mid) ? (lc[u] = modify(lc[rt], l, mid, pos)) : (rc[u] = modify(rc[rt], mid + 1, r, pos));
return u;
}
int query(int rt0, int rt1, int l, int r, int pos) {
if(l == r) return l;
/**/ int res = t[lc[rt1]] - t[lc[rt0]], mid = (l + r) >> 1;
return (res >= pos) ? (query(lc[rt0], lc[rt1], l, mid, pos)) : (query(rc[rt0], rc[rt1], mid + 1, r, pos - res));
}
}
namespace INIT {
void Main() {
n = read(), k = read(); L = read(), R = read();
rep(i, 1, n) a[i] = read(), W[i + 1] = (s[i] = s[i - 1] + a[i]);
sort(W + 1, W + n + 2);
d = unique(W + 1, W + n + 2) - W - 1;
rep(i, 0, n) Ns[i] = lower_bound(W + 1, W + d + 1, s[i]) - W;
}
}
namespace SOLVE {
using namespace Chairman;
struct node {
int pos, kth;
LL val;
};
int cmp(node tarA, node tarB) { return tarA.val < tarB.val;}
Heap <node, cmp> hep;
void Main() {
rt[0] = build(1, d), rt[1] = modify(rt[0], 1, d, Ns[0]);
rep(i, 1, n) rt[i + 1] = modify(rt[i], 1, d, Ns[i]);
rep(i, 1, n) {
int bound1 = max(i - R, 0), bound2 = i - L;
if(bound2 < bound1) continue;
int cur = query(rt[bound1], rt[bound2 + 1], 1, d, 1);
hep.push((node){i, 1, s[i] - W[cur]});
}
LL ans = 0;
rep(i, 1, k) {
node Tmp = hep.pop();
ans += Tmp.val;
int bound1 = max(Tmp.pos - R, 0), bound2 = Tmp.pos - L;
if(Tmp.kth + 1 > bound2 - bound1 + 1) continue;
int cur = query(rt[bound1], rt[bound2 + 1], 1, d, Tmp.kth + 1);
hep.push((node){Tmp.pos, Tmp.kth + 1, s[Tmp.pos] - W[cur]});
}
cout << ans << endl;
}
}
int main() {
#ifdef Qrsikno
freopen("BZOJ2006.in", "r", stdin);
freopen("BZOJ2006.out", "w", stdout);
#endif
INIT :: Main();
SOLVE :: Main();
#ifdef Qrsikno
debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
return IO.flush();
}
BZOJ2006 超级钢琴的更多相关文章
- [NOI2010][bzoj2006] 超级钢琴 [主席树/ST表+堆]
题面: 传送门 思路: 首先容易想到用堆维护的O(n2logn)暴力 那么肯定就是在这个基础上套数据结构了[愉快] 然而我因为过于蒟蒻......只想得到主席树暴力***过去的方法 大概就是把前缀和算 ...
- bzoj2006 noi2010 超级钢琴 主席树 + 优先队列
Time Limit: 20 Sec Memory Limit: 552 MBSubmit: 2435 Solved: 1195 Description 小 Z是一个小有名气的钢琴家,最近C博士送 ...
- 【BZOJ2006】超级钢琴(主席树,优先队列)
[BZOJ2006]超级钢琴(主席树,优先队列) 题面 BZOJ 题解 既然是一段区间 首先就要变成单点 所以求一个前缀和 这个时候贪心很明显了: 枚举每一个点和可以和它组成一段的可行的点 全部丢进一 ...
- bzoj2006 [NOI2010]超级钢琴 (及其拓展)
bzoj2006 [NOI2010]超级钢琴 给定一个序列,求长度在 \([L,\ R]\) 之间的区间和的前 \(k\) 大之和 \(n\leq5\times10^5,\ k\leq2\times1 ...
- 【BZOJ2006】【NOI2010】超级钢琴(主席树,优先队列)
[BZOJ2006]超级钢琴(主席树,优先队列) 题面 BZOJ 题解 既然是一段区间 首先就要变成单点 所以求一个前缀和 这个时候贪心很明显了: 枚举每一个点和可以和它组成一段的可行的点 全部丢进一 ...
- 【BZOJ2006】[NOI2010]超级钢琴 ST表+堆
[BZOJ2006][NOI2010]超级钢琴 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以 ...
- 【BZOJ-2006】超级钢琴 ST表 + 堆 (一类经典问题)
2006: [NOI2010]超级钢琴 Time Limit: 20 Sec Memory Limit: 552 MBSubmit: 2473 Solved: 1211[Submit][Statu ...
- BZOJ2006[NOI2010]超级钢琴——堆+主席树
题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中 ...
- bzoj千题计划162:bzoj2006: [NOI2010]超级钢琴
http://www.lydsy.com/JudgeOnline/problem.php?id=2006 输出最大的k个 sum[r]-sum[l-1] (L<=r-l+1<=R) 之和 ...
随机推荐
- 系统优化(一)Maven打包同一个jar有不同的:版本号+时间戳(解决思路)
解决:maven仓库的ear里面有非常多个同样的jar(仅仅是包括不同的:版本号+时间戳) 问题描写叙述: 发现ear里面有非常多个同样的jar,仅仅是包括不同的:版本号+时间戳,例如以下图所看到的: ...
- Design Pattern Visitor 訪问者设计模式
訪问者设计模式是已经有了一组Person对象了,然后不同的訪问者訪问这组对象.会有不同效果. 这些訪问者实际上就是一个能够让Person对象组运行的动作行为等. 至于这些Person对象是怎样运行这些 ...
- IOS开发 ios7适配
ios7控制器试图默认为全屏显示,导航栏的不同设置会产生不同的效果. 首先判断系统的的版本,区别: if (floor(NSFoundationVersionNumber) <= NSFound ...
- 电脑控制手机的另一选择——android vnc server
近来发现的Android上的原生VNC Server,就是说只要手机上安装并运行这个软件,即可实现电脑上查看并控制手机了. 首先是手机端. 1)下载androidvncserver: http://c ...
- srand rand 随机函数
srand函数是随机数发生器的初始化函数.原型:voidsrand(unsigned int seed); srand和rand()配合使用产生伪随机数序列.rand函数在产生随机数前,需要系统提供的 ...
- 【转载】SOAP协议介绍
SOAP是用在分散或分布的环境中交换信息的简单的协议,它是一个基于XML的协议,包括三个部分:封装定义了一个描述消息中包含什么内容以及如何处理它们的框架,编码规则用于表示应用程序定义的数据类型的实例, ...
- iOS + Nodejs SSL/Https双向认证
移动互联网的大力发展,安全越来越重要. 什么是双向认证呢?双向认证就是client要验证server的合法性,同一时候server也要验证client的合法性. 这样两方都相互验证,提高安全性. 关于 ...
- 10 逻辑完善以及bug修复
进行到这里,我们应用开发已经接近尾声,我这里基本就是应用开发的记录过程,讲解的东西很少,有问题可以在评论区讨论呦.下面进入最后调整的阶段. 预览我们的应用,会发现首页的职位列表,也会显示收藏的星星图标 ...
- dotnet new 命令
如果想知道这个命令的详细用法,可以在打完命令之后,在输入一个" --help"即可 $ dotnet new --help.NET Initializer Usage: dotne ...
- js简易美丽的提示框
<span style="font-size:14px;">function showTips(txt, time, status) { var htmlCon = ' ...