HDU 1512 Monkey King(左偏树+并查集)
2015-07-28 09:39
405 查看
题目链接:Click here
题意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个能力值,能力值越大表示这个猴子越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中能力最强的出来决斗,决斗的2个猴子力量值减半,然后这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最厉害的猴子单挑,求决斗完后这拨猴子力量最大值。
思路:两拨不认识得猴子决斗后认识,涉及到合并,于是想到并查集。又要求两拨猴子的最强战斗力,大顶堆比较合适,而堆得合并,用到了刚看到的左偏树。
代码:
题意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个能力值,能力值越大表示这个猴子越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中能力最强的出来决斗,决斗的2个猴子力量值减半,然后这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最厉害的猴子单挑,求决斗完后这拨猴子力量最大值。
思路:两拨不认识得猴子决斗后认识,涉及到合并,于是想到并查集。又要求两拨猴子的最强战斗力,大顶堆比较合适,而堆得合并,用到了刚看到的左偏树。
左偏树:(引用百度百科) [性质1] 节点的键值小于或等于它的左右子节点的键值。 [性质2] 节点的左子节点的距离不小于右子节点的距离。 [性质3] 节点的距离等于它的右子节点的距离加1。 我们的印象中,平衡树是具有非常小的深度的,这也意味着到达任何一个节点所经过的边数很少。左偏树并不是为了快速访问所有的节点而设计的,它的目的是快速访问最小节点以及在对树修改后快速的恢复堆性质。从图中我们可以看到它并不平衡,由于性质2的缘故,它的结构偏向左侧,不过距离的概念和树的深度并不同,左偏树并不意味着左子树的节点数或是深度一定大于右子树。
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <cstdlib> using namespace std; int father[100005]; struct Monkey { int left, right; int dis; int blood; } LTree[100005]; int findx(int x) { if(x == father[x])return x; return father[x] = findx(father[x]); } int merges(int x,int y) { int left, right; if( x == 0 ) return y; if( y == 0) return x; if( LTree[x].blood < LTree[y].blood) //大顶堆 swap(x,y); LTree[x].right = merges(LTree[x].right,y); left = LTree[x].left; right = LTree[x].right; father[right] = x; //修改并查集的根 if(LTree[left].dis < LTree[right].dis) swap(LTree[x].left,LTree[x].right); if(LTree[x].right == 0) LTree[x].dis = 0; else LTree[x].dis = LTree[LTree[x].right].dis + 1; return x; } int del(int x) {//删除根节点,并合并左右子树 int left, right; left = LTree[x].left; right = LTree[x].right; father[left] = left; father[right] = right; LTree[x].lef 4000 t = LTree[x].right = LTree[x].dis = 0; return merges(left, right); } void fight(int a,int b) {//两棵树根节点血量减半,并与子树再次合并 int left,right; LTree[a].blood /= 2; LTree[b].blood /= 2; left = del(a); right = del(b); left = merges(left, a); right = merges(right, b); left = merges(left,right); printf("%d\n",LTree[left].blood); } int main() { int n, m, x, y, a, b; while(scanf("%d",&n) != EOF) { for(int i = 1; i <= n; i++) { scanf("%d",<ree[i].blood); LTree[i].left = 0; LTree[i].right = 0; LTree[i].dis = 0; father[i] = i; } scanf("%d",&m); for(int i = 1; i <= m; i++) { scanf("%d%d",&x,&y); a = findx(x); b = findx(y); if(a == b) printf("-1\n"); else fight(a, b); } } return 0; }