bzoj1367 可并堆
参考:《左偏树的特点及运用——黄河源》
我们将这个数列划为很多个互不相交的区间,每一段区间内的 \(b\) 是相等的,即
- \(b[l[i]]=b[l[i]+1]=...=b[r[i]]=w[i]\), \(l[i],r[i]\) 为区间 \(i\) 的左右端点
先假设题目时要求b不下降的(比较好讨论),那么答案应该会呈现出这样子:
定理一:对于单个区间的最优解为其中位数,即 \(a[l[i]],a[l[i]+1],...,a[r[i]]\) 的最优解为 \(b[l[i]]=b[l[i]+1]=...=b[r[i]]=\) 中位数。
- 由绝对值的几何意义可得.
如果我们将"b不下降"这一条件忽略
,单纯考虑单个区间的最优解,b可能是这样的:
在讨论如何将不合法的最优解
转化为合法的最优解
之前,先来了解一些结论:
结论一:对于一段连续的a不下降(可能由多个区间组成),则 \(b[i]=a[i]\) 时为最优解。
证明:该段绝对值之差为0.
引理一:对于相邻的两个区间 \([l[i]],\ r[i]]\ and\ [l[i+1],\ r[i+1]]\) , \(u,v\) 为其最优解,若 \(u\le v\), 则 \([l[i],r[i+1]]\) 的区间最优解为 \(b[l[i]]=b[l[i]+1]=...=b[r[i]]=u,\ b[l[i+1]]=b[l[i+1]+1]=...=b[r[i+1]]=v\).
证明:子问题最优 -> 整体最优.
引理二:对于相邻的两个区间 \([l[i]],\ r[i]]\ and\ [l[i+1],\ r[i+1]]\) , \(u,v\) 为其最优解,若 \(v < u\) ,则 \(b[r[i]]\le u, v\le b[l[i+1]].\)
画个图:
因为除此之外的情况(虚线)一定不会比这种情况更好
如:上面那条虚线没有u+右边部分
更优,下面那条虚线没有v+左边部分
更优
而u+右边部分
与v+左边部分
是属于红色折线的.
结论二:对于任意一个序列 \(a[1] , a[2] , ... , a[n]\) ,如果最优解为 \(( u , u , ... , u )\) , 那么在满足\(u ≤ u'\le b[1] \ or \ b[n] \le u' ≤ u\) 的情况下,\(( b[1] , b[2] , ... , b[n] )\) 不会比 \(( u′ , u′ , ... , u′ )\)更优。
给出 \(u\le u'\le b[1]\) 的证明,后者类似可证.
证明:
对于 \(n=1,a[1]=u,\) 显然成立.
假设对于n是成立的,那么将 \(b[1],b[2]...b[n],b[n+1]\) 都设为 \(b[1]\) , 若解变得更坏了,则最优解应该是 \((u,u,...,u,b[n+1])\) 而不是 \((u,u,...u,u)\), 而由几何意义得 \((b[1],b[1]...b[1])\) 比 \((u',u',...,u')\) 会差,故对于 \(n+1\) 也成立.
由数学归纳原理可得命题成立.
至此,我们已经可以将局部最优解合成整体最优解了!
一:
u,v为两段区间的最优解,由引理一
全局最优解为 \((u,u,...,u,v,v,...,v)\).
二:
这种情况较为复杂,由引理二
可得最优解一定是左边
\(\le u\), 右边
的 \(\geq v\),即为红色部分
,
又由结论二
得虚线部分比红色部分更优(其实是不会更差), 所以这个整个区间的最优解一定为一个定值!
注:其实左边的虚线是比右边低的,但是左边的虚线越往上越优,右边的虚线越往下越优,故最优时它们高度相同,为一定值。
接下来就转换成求这个定值了。
由定理一
,值该定值即为整个数列的中位数!!
所以一开始假设每个数就是一个区间,然后不断合并区间,最终知道全局最优解。
- 假设我们已经找到前 \(k\) 个数 \(a[1], a[2], ... , a[k] (k<n)\) 的最优解,
- 得到 \(m\) 个区间组成的队列, 对应的解为 \((w[1], w[2] , ... , w[m])\),
- 现在要加入 \(a[k+1]\), 并求出前 \(k+1\) 个数的最优解。
- 首先我们把 \(a[k+1]\) 作为一个新区间直接加入队尾,令 \(w[m+1]=a[k+1]\) ,
- 然后不断检查队尾两个区间的解 \(w[m]\) 和 \(w[m+1]\),如果 \(w[m] > w[m+1]\) ,
- 我们需要将最后两个区间合并,并找出新区间的最优解(也就是序列 \(a\) 中,下标在这个新区间内的各项的中位数)。
- 重复这个合并过程,直至 \(w[1] ≤ w[2] ≤ ... ≤ w[m]\) 时结束,然后继续处理下一个数。
- 画图理解...
现在我们需要考虑一下数据结构的选取,
算法中涉及到以下两种操作:
1.合并两个有序集
2.查询某个有序集内的中位数
我们很容易想到平衡树
,但是就算是启发式合并
,复杂度也有 \(O(nlog^2n)\), \(1e6\) 过不了.
我们可以用大根堆
来维护每个区间内的中位数
,我们发现右端的堆都是单个
元素的加入,只要一下降
,就会合并,所以合并是正确的。
“通过进一步分析,我们发现,只有当某一区间内的中位数比后一区间内的中位数大时,合并操作才会发生
,也就是说,任一区间与后面的区间合并后,该区间内的中位数不会变大
。于是我们可以用最大堆来维护每个区间内的中位数,当堆中的元素大于该区间内元素的一半
时,删除堆顶元素,这样堆中的元素始终为区间内较小的一半元素
,堆顶元素即为该区间内的中位数
。” —— 黄源河
堆顶元素即为该区间内的中位数。
考虑到我们必须高效地完成合并操作,左偏树
是一个理想的选择,每个操作都是 \(O(logn)\),
总时间复杂度 \(O(nlogn)\).
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int read() {
register int x = 0, f = 1; register char c;
while (!isdigit(c = getchar())) if (c == '-') f = -1;
while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getchar()));
return x * f;
}
const int N = 1e6 + 3;
int n, l[N], r[N], tot[N], b[N], size[N], dis[N] = {-1}, val[N], root[N], ch[N][2], w[N];
int merge(int x, int y) {
if (!x) return y;
if (!y) return x;
if (val[x] < val[y]) swap(x, y);
ch[x][1] = merge(ch[x][1], y);
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
if (dis[ch[x][0]] < dis[ch[x][1]]) swap(ch[x][1], ch[x][0]);
dis[x] = dis[ch[x][1]] + 1;
return x;
}
int main() {
freopen("xhc.in", "r", stdin);
freopen("xhc.out", "w", stdout);
n = read();
for (int i = 1; i <= n; ++ i) val[i] = read(), val[i] -= i;
int now = 0;
for (int i = 1; i <= n; ++ i) {
now ++;
l[now] = r[now] = i;
root[now] = i;
tot[now] = size[root[now]] = 1;
while (now > 1 and val[root[now - 1]] > val[root[now]]) {
now --;
r[now] = r[now + 1], tot[now] += tot[now + 1];
root[now] = merge(root[now], root[now + 1]);
while (size[root[now]] * 2 > (tot[now] + 1)) {
root[now] = merge(ch[root[now]][0], ch[root[now]][1]);
}
}
}
long long ans = 0;
for (int i = 1; i <= now; ++ i) {
for (int j = l[i]; j <= r[i]; ++ j) {
ans += 1ll * (val[root[i]] - val[j] < 0 ? val[j] - val[root[i]] : val[root[i]] - val[j]);
}
}
printf("%lld\n", ans);
/* for (int i = 1; i <= now; ++ i) {
for (int j = l[i]; j <= r[i]; ++ j) {
cout << val[root[i]] + j << " ";
}
}*/
}
bzoj1367 可并堆的更多相关文章
- BZOJ1367 [Baltic2004]sequence 堆 左偏树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1367 题意概括 Description Input Output 一个整数R 题解 http:// ...
- 【bzoj1367】[Baltic2004]sequence 可并堆
题目描述 输入 输出 一个整数R 样例输入 7 9 4 8 20 14 15 18 样例输出 13 题解 可并堆,黄源河<左偏树的特点及其应用>Page 13例题原题 #include & ...
- 可并堆试水--BZOJ1367: [Baltic2004]sequence
n<=1e6个数,把他们修改成递增序列需把每个数增加或减少的总量最小是多少? 方法一:可以证明最后修改的每个数一定是原序列中的数!于是$n^2$DP(逃) 方法二:把$A_i$改成$A_i-i$ ...
- 【BZOJ1367】【Baltic2004】sequence - 可合并堆
题意: 题解: 其实这是道水题啦……只不过我没做过而已 先考虑构造不严格递增序列,考虑原序列中的一段下降区间,显然区间中的$z$全取中位数最优: 那么可以把原序列拆成很多个下降序列,从头到尾加入原序列 ...
- 【BZOJ-1367】sequence 可并堆+中位数
1367: [Baltic2004]sequence Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 932 Solved: 348[Submit][S ...
- BZOJ1367 BOI2004Sequence(左偏树)
首先考虑把bi和ai同时减i,问题变为非严格递增.显然如果a是一个递减序列,b序列所有数都取其中位数最优.于是划分原序列使得每一部分递减,然后考虑合并相邻两段.如果前一段的中位数<=后一段的中位 ...
- BZOJ1367 [Baltic2004]sequence 【左偏树】
题目链接 BZOJ1367 题解 又是一道神题,, 我们考虑一些简单的情况: 我们先假设\(b_i\)单调不降,而不是递增 对于递增序列\(\{a_i\}\),显然答案\(\{b_i\}\)满足\(b ...
- BZOJ1367【Baltic2004】sequence
题面 Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Output 13 Hint 所求的Z序列为6,7, ...
- Java 堆内存与栈内存异同(Java Heap Memory vs Stack Memory Difference)
--reference Java Heap Memory vs Stack Memory Difference 在数据结构中,堆和栈可以说是两种最基础的数据结构,而Java中的栈内存空间和堆内存空间有 ...
随机推荐
- tomcat的下载和启动
1.下载和解压 把下载好的压缩包解压,放到想刚的目录里 看一下目录: 目录介绍: 2. 启动和访问 启动步骤: 如果startup.bat 双击执行脚本一闪而过,解决方法: 第一可能是:没有配置JAV ...
- 使用TestFlight测试时候相关内容
前言:记录一下使用TestFlight测试时候相关内容 场景:在我们添加测试员:给测试员发送了邀请:测试员使用TestFlight的时候,其实是有崩溃的次数的记录的,相应的崩溃的信息也是可以查询到的. ...
- ajax请求相关问题
Ajax中async:false/true的作用: async. 默认是 true,即为异步方式,$.ajax执行后,会继续执行ajax后面的脚本,直到服务器端返回数据后,触发$.ajax里的succ ...
- ccenteros 部署 redis
step one : yum install redis -- 安装redis数据库 step two:安装完成之后开启redis 服务 service redis start syste ...
- Git工作流指南:Gitflow工作流
git工作流 1.Git flow 核心分支:master,dev 可能还会有:功能分支,bug修复分支,预发布分支 2.github flow:只一个长期分支,就是master 第一步:根据需求,从 ...
- Mybatis中使用UpdateProvider注解实现根据主键批量更新
Mapper中这样写: @UpdateProvider(type = SjjcSqlProvider.class, method = "updateTaskStatusByCBh" ...
- JQuery实现注册表单验证
效果图如下: 注册页面HTML代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &qu ...
- VULTR的VPS在centos的操作系统中出现网站无法访问 80端口被firewall禁止
导语:叶子在为一位客户配置web服务器环境的时候,出现网站不能访问的情况,但ping正常.客户的服务器是在VULTR上购买的VPS,安装的操作系统为centos 7.3.经过叶子的分析,认为是防火墙阻 ...
- GET POST 请求的详细区别
前言: 作为最常见的请求方式 在面试很有可能会被问到 所以在这里做一个简单总结 GET get方法向页面请求发送参数 地址和参数之间用?进行分割 例如 localhost:80/download.ht ...
- U盘被分区后恢复方法
一:运行cmd 二:输入diskpart,按enter. 三:输入list disk,按enter. 四:选择优U盘,输入select disk X(X代表磁盘后面的数字0.1,可磁盘的大小来判断数字 ...