1367: [Baltic2004]sequence

Description

Input

Output

一个整数R

Sample Input

7
9
4
8
20
14
15
18

Sample Output

13

HINT

所求的Z序列为6,7,8,13,14,15,18.
R=13

Source

【分析】

  这题主要是要证明结论。详见hyh的论文。

  先说说结论做法:

  把序列分成m个区间,每个区间最后到达的值都是u。u为这个区间所有数的中位数。

  先做一个小小的转化,题目要求b1<b2<...b3,可以变成b1-1<=b2-2<=b3-3<=...bi-i...【经典的标号的加减,加上一个等号

  然后是这样做:

假设我们已经找到前 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] 时结束,然后继续处理下一个数。

  正确性证明:

  若某序列前半部分 a[1], a[2], … , a[n] 的最优解为 (u,u,…,u),后半部分a[n+1], a[n+2], ... , a[m] 的最优解为 (v,v,…,v),那么整个序列的最优解是什么
呢?

  若 u≤ v,显然整个序列的最优解为 (u,u,…,u,v,v,…,v) 。

  否则,设整个序列的最优解为 ( b[1],b[2],…,b[m] ),则显然 b[n] ≤ u(否则我们把前半部分的解( b[1],b[2], …,b[n]) 改为 (u,u,…,u),由题设知整个序列的解不会变坏),同理b[n+1] ≥ v。

  接下来,我们将看到下面这个事实:
对于任意一个序列 a[1] ,a[2],…,a[n],如果最优解为 (u,u,…,u),那么在满足u≤ u′≤ b[1] 或 b[n] ≤ u′≤ u 的情况下, (b[1],b[2],…,b[n]) 不会比 ( u′ ,u′ ,…,u′ )
更优。

  我们用归纳法证明 u≤ u′≤ b[1] 的情况, b[n] ≤ u′≤ u 的情况可以类似证明。

  当 n=1 时, u=a[1],命题显然成立。
当n>1 时,假设对于任意长度小于n的序列命题都成立,现在证明对于长度
为n的序列命题也成立。

  首先把 (b[1], b[2], … b[n]) 改为 (b[1], b[1], … b[1]),这
一改动将不会导致解变坏,因为如果解变坏了,由归纳假设可知a[2],a[3],…,a[n]
的中位数w>u,这样的话,最优解就应该为(u,u,…,u,w,w,…,w),矛盾。

  然后我们再把(b[1],b[1],…,b[1])改为 ( u′ ,u′ ,…,u′ ),由于 | a[1] - x | + | a[2] - x | + …+ | a[n] - x | 的几何意义为数轴上点x到点a[1], a[2], … a[n] 的距离之和,且u≤ u′≤ b[1],显然点u′ 到各点的距离之和不会比点b[1] 到各点的距离之和大,也
就是说, (b[1],b[1],…,b[n]) 不会比 (v,v,…,v) 更优。(证毕)

  再回到之前的论述,由于 b[n] ≤ u,作为上述事实的结论,我们可以得知,
将 ( b[1],b[2],…,b[n] ) 改为 (b[n],b[n],…,b[n]),再将 ( b[n+1],b[n+2],…,b[m])
改为 ( b[n+1],b[n+1], …,b[n+1]),并不会使解变坏。

也就是说,整个序列的最优
解为 ( b[n],b[n],…,b[n],b[n+1],b[n+1],…,b[n+1])。再考虑一下该解的几何意
义,设整个序列的中位数为 w,则显然令 b[n]=b[n+1]=w 将得到整个序列的最优
解,即最优解为 (w,w,…,w)。

  (以上证明来自论文ORZ)

代码:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. using namespace std;
  7. #define Maxn 1000010
  8. #define LL long long
  9.  
  10. int a[Maxn];
  11.  
  12. int myabs(int x) {return x<?-x:x;}
  13.  
  14. struct node
  15. {
  16. int v,siz,dis,lc,rc;
  17. }t[Maxn];
  18.  
  19. struct Ltree
  20. {
  21. int cnt;
  22. int merge(int x,int y)
  23. {
  24. if(x==||y==) return x+y;
  25. if(t[x].v<t[y].v) swap(x,y);
  26. t[x].rc=merge(t[x].rc,y);
  27. t[x].siz=t[t[x].lc].siz+t[t[x].rc].siz+;
  28. if(t[t[x].rc].dis>t[t[x].lc].dis) swap(t[x].lc,t[x].rc);
  29. t[x].dis=t[t[x].rc].dis+;
  30. return x;
  31. }
  32. inline int top(int x) {return t[x].v;}
  33. inline int size(int x) {return t[x].siz;}
  34. inline void pop(int &x) {x=merge(t[x].lc,t[x].rc);}
  35. inline int add(int x)
  36. {
  37. t[++cnt].v=x;t[cnt].siz=;
  38. t[cnt].lc=t[cnt].rc=t[cnt].dis=;
  39. return cnt;
  40. }
  41. }heap;
  42.  
  43. int rt[Maxn],tot[Maxn];//区间
  44. int l[Maxn],r[Maxn];
  45.  
  46. int main()
  47. {
  48. int n;
  49. scanf("%d",&n);
  50. for(int i=;i<=n;i++) {scanf("%d",&a[i]);a[i]-=i;}
  51. int now=;
  52. for(int i=;i<=n;i++)
  53. {
  54. now++;
  55. rt[now]=heap.add(a[i]);
  56. l[now]=r[now]=i;tot[now]=;
  57. while(now>&&heap.top(rt[now-])>heap.top(rt[now]))
  58. {
  59. now--;
  60. rt[now]=heap.merge(rt[now],rt[now+]);
  61. tot[now]+=tot[now+];r[now]=r[now+];
  62. while(heap.size(rt[now])*>tot[now]+)
  63. heap.pop(rt[now]);
  64. }
  65. }
  66. LL ans=;
  67. for(int i=;i<=now;i++)
  68. {
  69. int xx=heap.top(rt[i]);
  70. for(int j=l[i];j<=r[i];j++)
  71. {
  72. ans+=myabs(a[j]-xx);
  73. }
  74. }
  75. printf("%lld\n",ans);
  76. return ;
  77. }

2017-01-16 15:30:21


左偏树:(上面的这份代码的左偏树还少了O(n)构建的部分。)

概念:

  优先队列 

  优先队列(Priority Queue)是一种抽象数据类型(ADT),它是一种容器,里面 有一些元素,这些元素也称为队列中的节点(node)。优先队列的节点至少要包含 一种性质:有序性,也就是说任意两个节点可以比较大小。为了具体起见我们假 设这些节点中都包含一个键值(key),节点的大小通过比较它们的键值而定。优 先队列有三个基本的操作:插入节点(Insert),取得最小节点(Minimum) 和删除 最小节点(Delete-Min)。

  可并堆

  可并堆(Mergeable Heap)也是一种抽象数据类型,它除了支持优先队列的三 个基本操作(Insert, Minimum, Delete-Min), 还支持一个额外的操作——合并操作。

  左偏树

  左偏树(Leftist Tree)是一种可并堆的实现。左偏树是一棵二叉树,它的节点 除了和二叉树的节点一样具有左右子树指针( left, right ) 外,还有两个属性:键值 和距离(dist)。

  1、外节点:节点 i 称为外节点(external node),当且仅当节点 i 的左子树或右子树为空 ( left(i) = NULL 或 right(i) = NULL );
  2、距离:点 i 的距离( dist( i ) ) 是节点 i 到它的后代 中,最近的外节点所经过的边数。特别的,如果节点 i 本身是外节点,则它的距 离为 0;而空节点的距离规定为-1 (dist(NULL) = -1)。在本文中,有时也提到一 棵左偏树的距离,这指的是该树根节点的距离。

左偏树的性质

[性质 1] 节点的键值小于或等于它的左右子节点的键值。
[性质 2] 节点的左子节点的距离不小于右子节点的距离。
[性质 3] 节点的距离等于它的右子节点的距离加 1
[引理 1] 若左偏树的距离为一定值, 则节点数最少的左偏树是完全二叉树。
[定理 1] 若一棵左偏树的距离为k,则这棵左偏树至少有 2k+1-1 个节点。
[性质 4] 一棵 N 个节点的左偏树距离最多为 [log(N+1)]-1。

性质4决定了左偏树的时间复杂度是较低的。

左偏树的合并:

  1. int merge(int x,int y)
  2. {
  3. if(x==0||y==0) return x+y;
  4. if(t[x].v<t[y].v) swap(x,y);
  5. t[x].rc=merge(t[x].rc,y);
  6. t[x].siz=t[t[x].lc].siz+t[t[x].rc].siz+1;
  7. if(t[t[x].rc].dis>t[t[x].lc].dis) swap(t[x].lc,t[x].rc);
  8. t[x].dis=t[t[x].rc].dis+1;
  9. return x;
  10. }

删除:

  1. inline void pop(int &x) {x=merge(t[x].lc,t[x].rc);}

添加一个节点形成一颗新的左偏树:

  1. inline int add(int x)
  2. {
  3. t[++cnt].v=x;t[cnt].siz=1;
  4. t[cnt].lc=t[cnt].rc=t[cnt].dis=0;
  5. return cnt;
  6. }

各种堆的比较:

左偏树真是真短真美丽233

2017-01-16 16:08:10

【BZOJ 1367】 1367: [Baltic2004]sequence (可并堆-左偏树)的更多相关文章

  1. BZOJ 2809: [Apio2012]dispatching(可并堆 左偏树板题)

    这道题只要读懂题目一切好说. 给出nnn个点的一棵树,每一个点有一个费用vvv和一个领导力aaa,给出费用上限mmm.求下面这个式子的最大值ax∗∣S∣ ( S⊂x的子树, ∑iv[i]≤m )\la ...

  2. 【BZOJ 2333 】[SCOI2011]棘手的操作(离线+线段树|可并堆-左偏树)

    2333: [SCOI2011]棘手的操作 Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边 ...

  3. [BOI2004]Sequence 数字序列(左偏树)

    PS:参考了黄源河的论文<左偏树的特点及其应用> 题目描述:给定一个整数序列\(a_1, a_2, - , a_n\),求一个递增序列\(b_1 < b_2 < - < ...

  4. USACO Running Away From the Barn /// 可并堆 左偏树维护大顶堆

    题目大意: 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于m的点有多少个 左偏树 https://blog.csdn.net/pengwill97/article/details/82 ...

  5. BZOJ1367 [Baltic2004]sequence 堆 左偏树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1367 题意概括 Description Input Output 一个整数R 题解 http:// ...

  6. BZOJ 2333: [SCOI2011]棘手的操作 可并堆 左偏树 set

    https://www.lydsy.com/JudgeOnline/problem.php?id=2333 需要两个结构分别维护每个连通块的最大值和所有连通块最大值中的最大值,可以用两个可并堆实现,也 ...

  7. BZOJ 5059: 前鬼后鬼的守护 可并堆 左偏树 数学

    https://www.lydsy.com/JudgeOnline/problem.php?id=5059 题意:将原序列{ai}改为一个递增序列{ai1}并且使得abs(ai-ai1)的和最小. 如 ...

  8. 【BZOJ 1455】 1455: 罗马游戏 (可并堆-左偏树+并查集)

    1455: 罗马游戏 Description 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那 ...

  9. 数据结构,可并堆(左偏树):COGS [APIO2012] 派遣

    796. [APIO2012] 派遣 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.  在这个帮派里,有一名忍者被称之为Master.除了Master以外,每名忍者都有且 ...

随机推荐

  1. debian 安装 android studio 环境

    jdk环境变量配置: ~/.hashrc export JAVA_HOME=/usr/share/jdk1.8.0_92 export PATH=$JAVA_HOME/bin:$PATH export ...

  2. HDU 3861 The King’s Problem(tarjan连通图与二分图最小路径覆盖)

    题意:给我们一个图,问我们最少能把这个图分成几部分,使得每部分内的任意两点都能至少保证单向连通. 思路:使用tarjan算法求强连通分量然后进行缩点,形成一个新图,易知新图中的每个点内部的内部点都能保 ...

  3. elasticsearch使用jetty进行简单的权限控制

    默认elasticsearch是使用netty作为http的容器,由于netty并没有权限模块,所以默认es没有任何的权限控制,直接通过http就可以进行任何操作,除非把http禁用.但如果你使用el ...

  4. USACO Section 1.4 Arithmetic Progressions 解题报告

    题目 题目描述 现在给你一个数集,里面的数字都是由p^2+q^2这种形式构成的0 <= p,q <= M,我现在需要你在其中找出一个长为N的等差数列,数列中的第一个数字为a,公差为b,当你 ...

  5. getWritableDatabase()与getReadableDatabase()的区别:

    getWritableDatabase取得的实例不是仅仅具有写的功能,而是同时具有读和写的功能同样的 getReadableDatabase取得的实例也是具对数据库进行读和写的功能. 两者的区别在于 ...

  6. AutoFac使用方法总结

    AutoFac是.net平台下的IOC容器产品,它可以管理类之间的复杂的依赖关系.在使用方面主要是register和resolve两类操作. 这篇文章用单元测试的形式列举了AutoFac的常用使用方法 ...

  7. SQL2005附加数据库时遇到的问题:用户组或角色在当前数据库已存在

    一次 附加备份数据库的 mdf 文件     成功后   创建登陆用户    但是  无法映射该用户的 对应数据库  出现 用户组或角色在当前数据库已存在 的问题 首先介绍一下sql server中“ ...

  8. 4-20ma电流信号转0-5v()

    源:4-20ma电流信号转0-5v 电压转电流电路原理图(0-5V转4-20mA) 4mA-20mA转0-5v电路问题,LM324一直输出10V

  9. C#入门经典(第五章-1)

  10. JavaScript 面向对象(一)

    参考:http://www.iteye.com/topic/1123555