正题

题目链接:https://www.luogu.com.cn/problem/P4331


题目大意

给出一个序列aaa,求一个单调上升的序列bbb使得∑i=1n∣ai−bi∣\sum_{i=1}^n|a_i-b_i|∑i=1n​∣ai​−bi​∣最小。


解题思路

巧妙的解法

首先我们让所有的ai−ia_i-iai​−i这样我们求的bbb序列就只需要满足单调不降。

然后考虑特殊情况

  • 对于一串连续的满足ax≤ax+1a_x\leq a_{x+1}ax​≤ax+1​那么这一段的bx=axb_x=a_xbx​=ax​
  • 对于一串连续的满足ax≥ax+1a_x\geq a_{x+1}ax​≥ax+1​那么这一段的bxb_xbx​为这一段数的中位数

而且对于连续的两个区间(L,mid)(L,mid)(L,mid)和(mid+1,R)(mid+1,R)(mid+1,R)的局部最优解也满足一下性质,所以就有做法:

我们维护若干段局部最优解www,每次加入一个数aia_iai​如果满足ai≥wcnta_i\geq w_{cnt}ai​≥wcnt​那么有bi=aib_i=a_ibi​=ai​。如果ai≤wcnta_i\leq w_{cnt}ai​≤wcnt​那么我们就将aia_iai​合并入前面的局部最优解,并重新计算这一段的中位数后继续看是否需要与前面合并(即判断是否wcnt≥wcnt−1w_{cnt}\geq w_{cnt-1}wcnt​≥wcnt−1​)。

我们可以左偏树做到动态合并和维护中位数(保持堆中个数为一半即可)。时间复杂度O(nlog⁡n)O(n\log n)O(nlogn)


codecodecode

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n,cnt,a[N],rt[N],L[N],R[N];
int t[N][2],dis[N],val[N],siz[N];
long long ans;
int Merge(int x,int y){if(!x||!y)return x+y;if(val[x]<val[y])swap(x,y);int &ls=t[x][0],&rs=t[x][1];rs=Merge(rs,y);if(dis[ls]<dis[rs])swap(ls,rs);dis[x]=dis[ls]+1;return x;
}
void Pop(int x)
{siz[x]--;rt[x]=Merge(t[rt[x]][0],t[rt[x]][1]);}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]-=i;for(int i=1;i<=n;i++){siz[++cnt]=1;val[i]=a[i];rt[cnt]=i;L[cnt]=R[cnt]=i;while(cnt>1&&val[rt[cnt-1]]>val[rt[cnt]]){cnt--;siz[cnt]+=siz[cnt+1];R[cnt]=R[cnt+1];rt[cnt]=Merge(rt[cnt],rt[cnt+1]);while(siz[cnt]>(R[cnt]-L[cnt])/2+1)Pop(cnt);}}for(int i=1;i<=cnt;i++)for(int j=L[i];j<=R[i];j++)ans+=abs(a[j]-val[rt[i]]);printf("%lld\n",ans);for(int i=1;i<=cnt;i++)for(int j=L[i];j<=R[i];j++)printf("%d ",val[rt[i]]+j);
}

P4331-[BalticOI2004]Sequence数字序列【左偏树】相关推荐

  1. P4331 [BalticOI 2004]Sequence 数字序列(左偏树)

    P4331 [BalticOI 2004]Sequence 数字序列 给定一个序列整数a1,a2,a3,-,an−1,ana_1, a_2, a_3, \dots, a_{n - 1}, a_na1​ ...

  2. 左偏树(可并堆)初步及其应用

    作者:hsez_yyh 链接:左偏树(可并堆)初步及其应用_hsez_yyh的博客-CSDN博客 来源:湖北省黄石二中信息竞赛组        著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  3. 《程序设计解题策略》——1.6 利用左偏树实现优先队列的合并

    本节书摘来自华章计算机<程序设计解题策略>一书中的第1章,第1.6节,作者:吴永辉 王建德 更多章节内容可以访问云栖社区"华章计算机"公众号查看. 1.6 利用左偏树实 ...

  4. 【学习笔记】浅谈短小可爱的左偏树(可并堆)

    文章目录 左偏树 左偏树的合并(merge)操作 例题 罗马游戏 [Apio2012]dispatching [JLOI2015]城池攻占 [Baltic2004]sequence 左偏树 左偏树是一 ...

  5. 一篇讲左偏树的好文章~

    传送门:http://blog.csdn.net/iaccepted/article/details/6748038 二.左偏树的定义和性质.............................. ...

  6. [2018.12.6]左偏树

    其实NOIp之前就学会了...结果咕到了现在... 我们都知道堆.但是很少有人会手写堆.因为我们有STL,而且手写堆码量不小(据说是吧?没写过). 而且堆的\(Merge\)操作又慢又麻烦. 于是就有 ...

  7. 左偏树初步学习 洛谷P3377

    玩的有点多......睡的有点少... 左偏树是一种支持O(logn)的时间复杂度内进行合并的堆式数据结构. 定义: 外结点:左儿子或者右儿子是空结点的结点 距离:一个结点x的距离disx定义为其子树 ...

  8. 可并堆——左偏树 Leftist Heap

    今天学习了左偏树,这是一个好理解而且好写的数据结构,和二叉堆一样可以在O(1)时间内取出优先级最高的值,O(logn)时间内删除优先级最高的值,不同的是如果要合并两个堆那么二叉堆就只能跪了.而左偏树能 ...

  9. Monkey King(左偏树 可并堆)

    我们知道如果要我们给一个序列排序,按照某种大小顺序关系,我们很容易想到优先队列,的确很方便,但是优先队列也有解决不了的问题,当题目要求你把两个优先队列合并的时候,这就实现不了了 优先队列只有插入 删除 ...

最新文章

  1. vs编译报错C1020: 意外的 #endif
  2. 《UML大战需求分析》阅读笔记1
  3. JVM - 再聊GC垃圾收集算法及垃圾收集器
  4. 数据分析项目某电商app行为数据分析(1)
  5. Maven组件通过命令上传本地和私有仓库
  6. 如何让代码更易于维护_易于使用的单位和集成代码
  7. 灰度拉伸python_灰度变换之灰度线性拉伸(算法1)
  8. PHP7语法知识(三):时间与日期、表单、类与对象、正则表达式、错误异常处理、图像处理...
  9. python循环引用例子_魔幻离现实仅一步之遥:细说Python的循环调用、循环引用和循环导入...
  10. Latex 安装与配置
  11. 2022-2027年中国北斗卫星导航系统行业市场调研及未来发展趋势预测报告
  12. Google Earth Pro v7.3.6.9285 谷歌地球卫星图像专业版
  13. github加速方法
  14. Promethues原理详解
  15. unity 2022大三期末大作业 3D立体魔方游戏(附下载链接)
  16. opencv 图像拼接和图像融合技术
  17. 计算机二级java邓伦单_全国计算机等级考试计算机基础及Photoshop应用试题答案(2)...
  18. elasticsearch - 节点、集群分片及副本、CRUD
  19. python将一个字符串反转并输出_逆转字符串—输入一个字符串,将其逆转并输出。...
  20. C语言开发情人节玫瑰

热门文章

  1. 有没有测试人心里的软件,心理测评,认识自己的有效工具:(二)你做的可能是假的心理测试...
  2. 面试官问:你做过什么Java线程池实践,我写了一篇博客给他看~
  3. 独占设备的分配与回收_灵魂拷问:Java对象的内存分配过程是如何保证线程安全的?...
  4. .net html5页面缓存,详解HTML5中的manifest缓存使用
  5. python分布式爬虫及数据存储_二十一 Python分布式爬虫打造搜索引擎Scrapy精讲—爬虫数据保存...
  6. 四川中级职称计算机考试考b级,四川省职称计算机B级考试1卷
  7. java的编译器怎么出来_怎样掌握ava编译器的使用,教程在这里,如何进行Java初级学习...
  8. AcWing 1047. 糖果
  9. linux查找应用主机,Linux 主机和服务器基本性能检查命令和工具
  10. 临界区、互斥量、信号量、事件的区别