HDU 1512 Monkey King(左偏树+并查集)
2015-07-27 19:05
405 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1512
题 意: 有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。
思 路:用并查集来处理猴子的朋友关系,用左偏树来做优先队列找出一只猴子所认识的猴子中战力最大者。
代码如下:
题 意: 有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。
思 路:用并查集来处理猴子的朋友关系,用左偏树来做优先队列找出一只猴子所认识的猴子中战力最大者。
代码如下:
#include <iostream> #include <stdio.h> #include <string.h> #include <deque> #include <stdlib.h> using namespace std; struct node { int l,r,dis,s; }vis[100005]; int father[100005]; int findx( int x ) { if( x != father[x] ) father[x] = findx( father[x] );//路径压缩,因为根结点所表示的数即为那一堆中的最大值 return father[x]; } int mergex( int x, int y ) { if( x == y ) return x;//是同一棵树 if( x == 0 ) return y;//x树是空数 if( y == 0 ) return x;//y树是空数 if( vis[x].s < vis[y].s ) swap(x,y);;//如果x树根值<y树根值,交换树根的指针,此句作用是保证x指针指向的左偏树根值大于y指针指向的左偏树根值 vis[x].r = mergex( vis[x].r, y );//将x数的右子树与y树合并并把合并后的树根置为x树的右子树 father[vis[x].r] = x;//将x树的左子树的所在的集合(由并查集所处理的互相认识的)的根结点指向x if( vis[vis[x].l].dis < vis[vis[x].r].dis ) swap( vis[x].l, vis[x].r );//如果x树的左子树的最近可插入位置小于右子树的最近可插入位置则交换左右孩子,此句维持左偏性质 vis[x].dis = vis[vis[x].r].dis + 1; return x; } int del( int x )//将左偏树的根结点去掉 { int l, r;//将x取出所在集合,并分为由左树与右树构成的两个集合 l = vis[x].l; r = vis[x].r; father[l]=l;//处理左树集合的根结点 father[r]=r;//处理右树集合的根结点 vis[x].l = vis[x].r = vis[x].dis = 0;//初始化 return mergex( l, r );//将左,右合并 } void solve( int x, int y ) { vis[x].s/=2;//争斗过后 vis[y].s/=2; int l,r; l=del(x);//将x左偏树的根结点去掉 r=del(y);//将y左偏树的根结点去掉 l=mergex(l,x);//将新的根结点插入树 r=mergex(r,y); l=mergex(l,r);//将两棵新树合并 printf("%d\n",vis[l].s); } int main() { int n; while( scanf ( "%d", &n ) != EOF ) { for( int i = 1 ; i <= n; i ++ ) { scanf ( "%d", &vis[i].s ); vis[i].l=vis[i].r=vis[i].dis=0; father[i]=i; } int m; scanf ( "%d", &m ); for( int i = 0; i < m; i ++ ) { int x, y; scanf ( "%d %d", &x, &y ); int fx = findx(x);//找最大值即根结点 int fy = findx(y); if( fx == fy ) printf("-1\n"); else solve(fx,fy); } } return 0; }
相关文章推荐
- Javascript SHA-1:Secure Hash Algorithm
- [转]可视化的数据结构和算法
- 统计文件中不小于某一长度的单词的个数(泛型算法实现)
- 使用他人的MD5编码类,修改形成密码串
- Extracting Structured Data from Web Pages
- (译)Cocos2d_for_iPhone_1_Game_Development_Cookbook:1.13使用CCTexture2DMutable调换调色盘
- Java中3DES加密
- Refactoring Notes-Refactoring Methods(3)
- 图书馆管理程序~~不过貌似功能!!有空再修修
- trainging contest#2(2011成都现场赛)I BY Hyoga
- C/C++头文件包含内容概览
- 堆栈的应用(1) 平衡符号 C++实现
- 程序员编程艺术第一章、左旋转字符串
- 程序员编程艺术:第三章续、Top K算法问题的实现
- 程序员编程艺术:第四章、现场编写类似strstr/strcpy/strpbrk的函数
- 十四、第三章再续:快速选择SELECT算法的深入分析与实现
- 程序员编程艺术:第七章、求连续子数组的最大和
- 程序员编程艺术:第八章、从头至尾漫谈虚函数
- 程序员编程艺术:第九章、闲话链表追赶问题
- 程序员编程艺术:第十章、如何给10^7个数据量的磁盘文件排序