c++ 左偏树简析 猴王例题讲解

本文介绍了猴王问题的背景及解决思路,重点解析了利用左偏树这一数据结构来高效地处理猴子之间的决斗,通过合并和查找操作保持树的平衡。左偏树的特点是任意节点的左子树深度大于等于右子树深度,适用于快速找到群体中的最强者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:猴王 Monkey King

题目描述

很久很久以前,在一个广阔的森林里,住着n只好斗的猴子。起初,它们各干各的,互相之间也不了解。但是这并不能避免猴子们之间的争吵,当然,这只存在于两个陌生猴子之间。当两只猴子争论时,它们都会请自己最强壮的朋友来代表自己进行决斗。显然,决斗之后,这两只猴子以及它们的朋友就互相了解了,这些猴子之间将再也不会发生争论了,即使它们曾经发生过冲突。
假设每一只猴子都有一个强壮值,每次决斗后都会减少一半(比如10会变成5,5会变成2.5)。并且我们假设每只猴子都很了解自己。就是说,当它属于所有朋友中最强壮的一个时,它自己会站出来,走向决斗场。

输入

输入分为两部分。
第一部分,第一行有一个整数n(n<=100000),代表猴子总数。
接下来的n行,每行一个数表示每只猴子的强壮值(小于等于32768)。
第二部分,第一行有一个整数m(m<=100000),表示有m次冲突会发生。
接下来的m行,每行包含两个数x和y,代表第x个猴子和第y个猴子之间发生冲突。

输出

输出每次决斗后在它们所有朋友中的最大强壮值。数据保证所有猴子决斗前彼此不认识。

样例输入
  5
  20
  16
  10
  10
  4
  4
  2 3
  3 4
  3 5
  1 5
样例输出
  8
  5
  5
  10

解析

首先,看到题目我们首先会想到,并查集和堆,因为我们每一次都要从一群猴子中找出最强壮的,暴力搜一遍显然不行,因此要用到堆,然后两只猴子打架后需要将两群猴子合并,因此要用到并查集,但是同时写这两种数据结构太麻烦,所以要借助一种既具有查找功能又具有合并功能的数据结构–左偏树。
下面简单讲一讲左偏树,首先定义几个概念,
1.外结点:左子树或右子数为空的结点即无左子树或右子树。
2.结点i的距离:结点i到后代最近的外结点的所经过的边数。
3.左偏性质:一棵左偏树中任意结点的左子结点距离大于右子节点距离。

上图摘自百度百科

图中外结点有18 20 19 24 15 30 28 11 21 16 42 50 33 26 27。
蓝色数字为该结点的距离。
由第二,三条概念得一个结点的距离一定是它右子结点(如果有)的距离+1,因为左子结点距离大于等于右子结点距离,结点距离又要求最近。

左偏树基本操作(大根为例):

1.合并操作(合并两棵左偏树):将两棵树中较大的根结点,作为合并后的树的根结点,将根较小的树与根较大的树的右子结点继续合并操作,直到无子结点。合并后如果不满足左偏树性质,即左子结点距离小于右子结点距离则维护,即交换指针。
2.插入(加入一个结点到树中):易得单个结点也属于左偏树,因此可以将单个结点视为一棵左偏树进行一次合并操作。
3.删除操作(删除根结点):合并左右两棵子树即可。

可以说实际上,左偏树就只有一种操作,合并。

上图(小顶树,跟我不一样):

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值