[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=34693563

向大(hei)佬(e)势力学(di)习(tou)

前段时间学的左偏树,今天复习了一遍,写篇博客加深印象。

左偏树是可合并堆中好写好理解的数据结构。其定义为:

1、满足堆的性质

2、节点的左子节点的距离不小于右子节点的距离

3、每一个子树也满足左偏树的性质

如图

然后这个“距离”懵逼了我好久。标准的定义是:

到最近的右儿子为空的节点的距离

可是单是知道定义,到底该怎么处理呢?直观感觉难查询难计算。那么,我们将其维护成某些特殊的状态:一直向右就是右子节点,就方便计算和维护了,于是还多了一条性质:”节点的距离等于它的右子节点的距离加1“,这个性质对于维护来说即为重要。

这里有一个小技巧:把空节点的dis设为-1,这样在维护的时候就不用分情况讨论了。

  1. a[x].dis=a[a[x].rs].dis+1;

当在合并时,可能会出现左子节点距离小于右子节点距离的情况,这时只需要将左右儿子交换即可

  1. if(a[a[x].ls].dis<a[a[x].rs].dis) swap(a[x].ls,a[x].rs);

现在重头戏来了,如何合并?

借用某大大的图解,我也是看了之后才理解到的

http://www.cnblogs.com/yc_sunniwell/archive/2010/06/28/1766756.html







由图可以看出,合并过程其实更像是“插入”过程,是将一棵树插入另一棵树。一直向右边走,以堆的性质为条件判断是谁插入谁。

由于维护了左偏的性质,dis最多就log层,所以时间上是不会爆的。

下面是最好模板化的代码

  1. int merge(int x,int y){
  2. if(x==0) return y;
  3. if(y==0) return x;
  4. if(a[x].key<a[y].key){
  5. swap(x,y);
  6. }
  7. a[x].rs=merge(a[x].rs,y);
  8. if(a[a[x].ls].dis<a[a[x].rs].dis) swap(a[x].ls,a[x].rs);
  9. a[x].dis=a[a[x].rs].dis+1;
  10. return x;
  11. }

插入和删除就很好写的,只不过是对merge进行一些花样操作

插入一个点,可以把这个点看做一棵树,merge就好了

删除其实就是把左右子树合并起来

好了,基础操作总结完了

然而左偏树常常与并查集连用,我认为把祖先指向堆顶元素会方便一些,但在处理时还是有点绕

下面由一道入门题结束吧

Problem Description

Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its own way and none of them knows each other. But monkeys can’t avoid quarrelling, and it only happens between two monkeys who does not know each other. And when it happens, both the two monkeys will invite the strongest friend of them, and duel. Of course, after the duel, the two monkeys and all of there friends knows each other, and the quarrel above will no longer happens between these monkeys even if they have ever conflicted.

Assume that every money has a strongness value, which will be reduced to only half of the original after a duel(that is, 10 will be reduced to 5 and 5 will be reduced to 2).

And we also assume that every monkey knows himself. That is, when he is the strongest one in all of his friends, he himself will go to duel.

Input

There are several test cases, and each case consists of two parts.

First part: The first line contains an integer N(N<=100,000), which indicates the number of monkeys. And then N lines follows. There is one number on each line, indicating the strongness value of ith monkey(<=32768).

Second part: The first line contains an integer M(M<=100,000), which indicates there are M conflicts happened. And then M lines follows, each line of which contains two integers x and y, indicating that there is a conflict between the Xth monkey and Yth.

Output

For each of the conflict, output -1 if the two monkeys know each other, otherwise output the strongness value of the strongest monkey in all friends of them after the duel.

Sample Input

5

20

16

10

10

4

5

2 3

3 4

3 5

4 5

1 5

Sample Output

8

5

5

-1

10

题目大意

有n只猴子,每只猴子有厉害值,一开始素不相识。

两只不熟的猴子相遇,它们会发生争执。然后,它们会邀请它们认识的最厉害的猴子决斗。决斗完这两只决斗的猴子的厉害值都会减半。决斗能促进友谊,这样这两拨素不相识的猴子就都认识了对方。

如果一只猴子不认识任何其他猴子,那么它就会亲自上阵。

每次给出两只猴子x,y,判断它们是否认识对方。若不认识,输出决斗后它们共同所在猴子群体中最厉害猴子的厉害值。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N=100000+5;
  6. struct Node {
  7. int ls,rs;
  8. int dis,key;
  9. }a[N];
  10. int fa[N],str[N],n,m;
  11. int getfa(int x){
  12. if(fa[x]==x) return x;
  13. return fa[x]=getfa(fa[x]);
  14. }
  15. int merge(int x,int y){
  16. if(x==0) return y;
  17. if(y==0) return x;
  18. if(a[x].key<a[y].key){
  19. swap(x,y);
  20. }
  21. a[x].rs=merge(a[x].rs,y);
  22. if(a[a[x].ls].dis<a[a[x].rs].dis) swap(a[x].ls,a[x].rs);
  23. a[x].dis=a[a[x].rs].dis+1;
  24. return x;
  25. }
  26. int main(){
  27. a[0].ls=a[0].rs=0;
  28. a[0].dis=a[0].key=-1;
  29. while(scanf("%d",&n)!=EOF){
  30. for(int i=1;i<=n;i++){
  31. scanf("%d",&str[i]);
  32. fa[i]=i;
  33. a[i].dis=0,a[i].key=str[i];
  34. a[i].ls=a[i].rs=0;
  35. }
  36. scanf("%d",&m);
  37. while(m--){
  38. int aa,bb;
  39. scanf("%d%d",&aa,&bb);
  40. int faa=getfa(aa),fab=getfa(bb);
  41. if(faa==fab){
  42. printf("-1\n");continue;
  43. }
  44. a[faa].key/=2,a[fab].key/=2;
  45. int tmpa=merge(a[faa].ls,a[faa].rs),tmpb=merge(a[fab].ls,a[fab].rs);
  46. a[faa].ls=a[faa].rs=a[fab].ls=a[fab].rs=0;
  47. fa[faa]=merge(faa,tmpa),fa[fab]=merge(fab,tmpb);
  48. fa[fa[faa]]=fa[faa],fa[fa[fab]]=fa[fab];
  49. faa=getfa(faa),fab=getfa(fab);
  50. int tmp=merge(faa,fab);
  51. fa[faa]=fa[fab]=tmp;
  52. printf("%d\n",a[tmp].key);
  53. }
  54. }
  55. return 0;
  56. }

左偏树自己的一点理解【hdu1512】【Monkey King】的更多相关文章

  1. [洛谷P3261] [JLOI2015]城池攻占(左偏树)

    不得不说,这道题目是真的难,真不愧它的“省选/NOI-”的紫色大火题!!! 花了我晚自习前半节课看题解,写代码,又花了我半节晚自习调代码,真的心态爆炸.基本上改得和题解完全一样了我才过了这道题!真的烦 ...

  2. [洛谷P1552] [APIO2012]派遣(左偏树)

    这道题是我做的左偏树的入门题,奈何还是看了zsy大佬的题解才能过,唉,我太弱了. 左偏树总结 Part 1 理解题目 很显然,通过管理关系的不断连边,最后连出来的肯定是一棵树,那么不难得出,当一个忍者 ...

  3. HDU1512 ZOJ2334 Monkey King 左偏树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - ZOJ2334 题目传送门 - HDU1512 题意概括 在一个森林里住着N(N<=10000)只猴子. ...

  4. [HDU1512]Monkey King(左偏树)

    用并查集维护猴子们的关系,强壮值用左偏树维护就行了 Code #include <cstdio> #include <algorithm> #include <cstri ...

  5. P3377 【模板】左偏树(可并堆) 左偏树浅谈

    因为也是昨天刚接触左偏树,从头理解,如有不慎之处,跪请指教. 左偏树: 什 么是(fzy说)左偏树啊? 前置知识: 左偏树中dist:表示到右叶点(就是一直往右下找,最后一个)的距离,特别的,无右节点 ...

  6. bzoj 1455: 罗马游戏 左偏树+并查集

    1455: 罗马游戏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 668  Solved: 247[Submit][Status] Descriptio ...

  7. luogu【P3377】 【模板】左偏树

    左偏树 顾名思义 向左偏的树 (原题入口) 它有啥子用呢??? 当然是进行堆的合并啦2333普通堆的合并其实是有点慢的(用优先队列的话 只能 一个pop 一个push 来操作 复杂度就是O(n log ...

  8. 『左偏树 Leftist Tree』

    新增一道例题 左偏树 Leftist Tree 这是一个由堆(优先队列)推广而来的神奇数据结构,我们先来了解一下它. 简单的来说,左偏树可以实现一般堆的所有功能,如查询最值,删除堆顶元素,加入新元素等 ...

  9. 浅谈左偏树在OI中的应用

    Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log ...

随机推荐

  1. 获取访问者ip及其所在城市

    原本使用新浪Api,然后发现不行了,以下小编重新查找了几个,个人推荐太平洋的接口 1.首先获取真实ip $ip = $_SERVER['REMOTE_ADDR']; 2.要知道的Api接口 几个接口$ ...

  2. Python全栈工程师(for、列表)

    ParisGabriel     Python 入门基础         for:用来遍历可迭代对象的数据元素可迭代对象是指以此获取数据元素的对象可迭代对象包括:字符串 str 列表 list元组 t ...

  3. 孤荷凌寒自学python第四十六天开始建构自己用起来更顺手一点的Python模块与类尝试第一天

     孤荷凌寒自学python第四十六天开始建构自己用起来更顺手一点的Python模块与类,尝试第一天 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 按上一天的规划,这是根据过去我自学其它编程语 ...

  4. kubeadm部署k8s1.9高可用集群--4部署master节点

    部署master节点 kubernetes master 节点包含的组件: kube-apiserver kube-scheduler kube-controller-manager 本文档介绍部署一 ...

  5. STL之list使用简介

    构造函数 list<int> c0; //空链表 list<); //建一个含三个默认值是0的元素的链表 list<,); //建一个含五个元素的链表,值都是2 list< ...

  6. js 图片自动循环切换setInterval();

    stlye样式定义 <style type="text/css">             body{background-image: url(img/001.jpg ...

  7. 【DNS】DNS的几个基本概念

    一. 根域 就是所谓的“.”,其实我们的网址www.baidu.com在配置当中应该是www.baidu.com.(最后有一点),一般我们在浏览器里输入时会省略后面的点,而这也已经成为了习惯. 根域服 ...

  8. LeetCode -- Sum Root to Leaf NNumbers

    Related Links: Path Sum: http://www.cnblogs.com/little-YTMM/p/4529982.html Path Sum II: http://www.c ...

  9. 全网把Map中的hash()分析的最透彻的文章,别无二家。

    你知道HashMap中hash方法的具体实现吗?你知道HashTable.ConcurrentHashMap中hash方法的实现以及原因吗?你知道为什么要这么实现吗?你知道为什么JDK 7和JDK 8 ...

  10. Linux系统——C/C++开发工具及环境搭建

    首先,我们是要在Linux下进行项目开发,让我们把windows“拆了”,装个Linux也是不可能的,会带来很多的不便,所以我们首先需要在虚拟机上安装Linux操作系统,我本次用的是CentOS,它也 ...