猴王

时间限制: 1 Sec  内存限制: 128 MB题目描述很久很久以前,在一个广阔的森林里,住着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.堆

堆很容易想到,因为每次我们都是找猴子及其朋友中的最强者来打一架,所以一个大根堆,就可以解决问题。但是每次找两个猴子是不是朋友很麻烦,需要O(n)的时间进行遍历,这就衍生出了第二种算法。

2.堆+并查集

既然只用堆查找需要较长时间,那使用一个并查集来进行查找即可方便快速的查找,但是新的问题又出现了,如何把两个猴子的朋友的强壮值合并在一起呢?要知道合并两个大根堆绝非易事。码代码就可以码得人神魂颠倒。自然是很不科学。

3.二叉搜索树

二叉搜索树运用到这个题上也并非不可,因为二叉搜索树,本身建树的过程有一定的规律性,即大于根节点的往右走,小于根节点往左走,这就使得它可以更简单的合并,但是时间上还是伤不起。

4.终极算法——可并二叉堆(当然是可以用Fibonacci堆,但实在是太难写了,博主完全不会)

利用可并堆,对两个堆用O(log n)的时间去合并,用O(1)的时间进行查找,可以达到我们预想的效果。在下面会有详细的讲解。

可并堆 名字里面有堆,说明这还是一个堆,但是它拥有合并的功能。可并堆同时又叫做左偏树,说明他本身的形状很像一棵树,可以像树一样进行遍历与查找,并且左偏、左偏,这棵树以左儿子为重。所以我们建树的时候就要往左边偏,当然你要往右边偏也没人拦得了你。

这里说一下,左偏树的几个基本概念。
1.定义一棵左偏树中的外结点为左子树或右子树为空的结点为外结点。
2.定义结点i的距离dist[i]为结点i到它后代中最近的外结点所经过的边数。
3.左偏性质:一颗左偏树中任意结点的左子结点的距离不小于右子结点的距离

左偏树有几种基本操作:

1.合并

int Merge(int a,int b)
{if(a==NULL) return b;if(b==NULL) return a;if(Tree[a].data<Tree[b].data) swap(a,b);Tree[a].rchild=Merge(Tree[a].rchild,b);if(Tree[a].rchild!=NULL) Tree[Tree[a].rchild].father=a;if(Tree[a].lchild!=NULL) Tree[Tree[a].lchild].father=a;if(Tree[Tree[a].lchild].dist<Tree[Tree[a].rchild].dist) swap(Tree[a].lchild,Tree[a].rchild);if(Tree[a].rchild==NULL) Tree[a].dist=0;else Tree[a].dist=Tree[Tree[a].rchild].dist+1;return a;
}
/*dist表示距离,因其左偏性质,我们自然是要在右距离的值比左距离的值大的时候交换一下,由于我们是储存的时候只储存了编号,换一下值就会连带着一起转移掉,所以无所谓了。*/

2.删除

int delet(int p)
{Tree[p].data/=2.0;int l=Tree[p].lchild;int r=Tree[p].rchild;Tree[l].father=l;Tree[r].father=r;Tree[p].dist=Tree[p].lchild=Tree[p].rchild=NULL;return Merge(l,r);
}
/*删除的时候就把根节点去掉,把它左儿子的父亲变为它自己,右儿子的父亲也变为它自己,合并左右两棵子树,再合并一下根节点。搞定!!!*/

下面放出猴王的代码:

//由于是道裸题就不在阐述太多,只有一些微弱的注释供诸君观赏
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxm=200010;
struct node{int lchild,rchild;int dist,father;int data;node(){lchild=NULL;rchild=NULL;dist=0;data=0;father=NULL;}
}Tree[maxm];//简单易懂的数组名
int n,m;
int inline readin() //蒟蒻的读入优化QAQ
{int x=0;char c=getchar();while(c>'9'||c<'0') c=getchar();while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x;
}
int Merge(int a,int b)//合并函数
{if(a==NULL) return b;if(b==NULL) return a;if(Tree[a].data<Tree[b].data) swap(a,b);Tree[a].rchild=Merge(Tree[a].rchild,b);if(Tree[a].rchild!=NULL) Tree[Tree[a].rchild].father=a;if(Tree[a].lchild!=NULL) Tree[Tree[a].lchild].father=a;if(Tree[Tree[a].lchild].dist<Tree[Tree[a].rchild].dist) swap(Tree[a].lchild,Tree[a].rchild);if(Tree[a].rchild==NULL) Tree[a].dist=0;else Tree[a].dist=Tree[Tree[a].rchild].dist+1;return a;
}
int delet(int p)//删除函数
{Tree[p].data/=2.0;int l=Tree[p].lchild;int r=Tree[p].rchild;Tree[l].father=l;Tree[r].father=r;Tree[p].dist=Tree[p].lchild=Tree[p].rchild=NULL;return Merge(l,r);
}
int search(int x)//其实可以用并查集,让程序跑得更快,但我懒得写了
{   if(Tree[x].father==x)return x;search(Tree[x].father);
}
void work()
{int A,B,p,q;for(int i=1;i<=m;i++){int x,y;x=readin(),y=readin();p=search(x);q=search(y);A=delet(p);//A为删除后左右子树合并的根节点B=delet(q);//B同AA=Merge(A,p);//合并A与改变了值的根节点B=Merge(B,q);//合并B与改变了值的根节点A=Merge(A,B);//合并全新的A Bprintf("%d\n",Tree[A].data);}
}
int main()
{n=readin();for(int i=1;i<=n;i++){Tree[i].data=readin();Tree[i].father=i;}m=readin();work();
}

Monkey King(猴王)——可并堆走起相关推荐

  1. [HDU1512]Monkey King(可并堆)

    题目: 我是超链接 题解: 可并堆的裸题,这次的操作是合并,删除,插入,插入的话就是把一个点merge到一个堆里,别的都是基本操作了 代码: #include <cstdio> #incl ...

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

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

  3. 有趣的排序算法——Monkey King排序 详细介绍

    <关于某位小蒟蒻在机房划水没事干于是瞎搞的那档事> 前言 排序算法在题目中经常需要用到,在程序中,我们一般打的是快排,归并,堆排等高效率排序,更有甚者会直接用sort排序,而今天,我要介绍 ...

  4. 洛谷1456 Monkey King

    题目:Monkey King 思路:左偏树.对于每次操作 x y ,先让x,y等于各自朋友中最大的那个,即x=find(x),y=find(y),然后再分别把x,y删除,修改权值后重新加入堆中. 代码 ...

  5. HDU 1512 Monkey King(左偏堆)

    爱争吵的猴子 ★★☆ 输入文件:monkeyk.in 输出文件:monkeyk.out 简单对比 时间限制:1 s 内存限制:128 MB [问题描述] 在一个森林里,住着N只好斗的猴子.开始,他们各 ...

  6. Monkey King【大根堆】

    题目链接 有N只孤独的猴子,然后他们会打M次架,每次打架的两只猴子战斗力减半,并且会成为朋友,朋友的朋友也是朋友,问的是朋友中战力最大的猴子是有多少战力? 于是,考虑维护这样的一个大根堆,每次将小的大 ...

  7. LuoguP1456 - Monkey King| 左倾堆 | 左偏树

    洛谷P1456 有n只猴子,每只猴子的战斗力为ai.m次操作,每次操作过后,猴子认识的猴子中(包括自己)战斗力最大的战斗力减半.操作后,两只猴子从不认识变为认识.输出打完架之后猴子认识的猴子中的最大战 ...

  8. 洛谷P1456 Monkey King

    题目描述 Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in ...

  9. Monkey King

    题目描述 Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in ...

最新文章

  1. P3项目全球模板狗血设置之一 --- 发货到成本中心需要输入Customer
  2. 导入python库linux_Linux下Python安装PyMySQL成功,但无法导入的问题
  3. 第十六周程序阅读(8)
  4. python语言入门pdf-Python语言入门.pdf
  5. Next-best-action marketing简介
  6. python提取html表格_想知道世界谁最有钱?3行Python代码告诉你
  7. 二叉树前序、中序和后序遍历的非递归实现
  8. 在webLogic 10.3中部署Hibernate 3.5出现 ClassNotFoundException解决办法
  9. win8.1 安装.NET Framework3.5
  10. IDEA java 运行程序 指定运行参数
  11. WebView 简单使用方法
  12. DisGeNet:疾病相关的基因与突变位点数据库
  13. 番茄时间管理法(Pomodoro Technique):一个番茄是如何让你工作更有效率的
  14. 《禅者的初心》读书笔记(2)
  15. 基于51单片机的交通灯仿真方案原理图设计一个数码管
  16. 【UVA 1589 --- Xiangqi】
  17. SAP - VL10B 执行采购订单,没有采购订单信息问题
  18. 一次累加序列折线图解释_如何解释非累加性措施第1部分按比例分配
  19. EXCEL如何批量调整图片大小?
  20. Quasi-Dense Similarity Learning for Multiple Object Tracking

热门文章

  1. Lpad与Rpad的用法
  2. 接口测试(http协议,get和post请求和响应)
  3. Eclipse3.4汉化包安装步骤
  4. 行情走势波动在各个时间段会有什么规律或变化?
  5. 关于WM_QUIT消息的牛刀解释
  6. scrapy 搜索关键字_解析搜索引擎抓取网站目标关键词原理
  7. 软件测试--应用JUnit进行单元测试
  8. Zigbee协议学习记录
  9. 我准备辞了月薪8k、工作20天的自由职业,干5k的单休工作
  10. QGraphicsScene添加Widget