HDU 1512 Monkey King 左偏树 + 并查集
2016-07-12 14:54
337 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1512
题意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。然后给出两个数字,代表两只猴子有矛盾要决斗,如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。
思路:学习左偏树。。。这篇很好左偏树的特点及其应用 ,维护每个猴子和他的朋友可以用并查集,然后维护他们之中最强的猴子则要用类似优先队列的数据结构,两拨猴子认识后就成了一拨,并查集要合并,维护战斗力的数据结构也要合并,用优先队列不能实现迅速合并,而左偏树就可以迅速的实现,因此用左偏树 + 并查集
题意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。然后给出两个数字,代表两只猴子有矛盾要决斗,如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。
思路:学习左偏树。。。这篇很好左偏树的特点及其应用 ,维护每个猴子和他的朋友可以用并查集,然后维护他们之中最强的猴子则要用类似优先队列的数据结构,两拨猴子认识后就成了一拨,并查集要合并,维护战斗力的数据结构也要合并,用优先队列不能实现迅速合并,而左偏树就可以迅速的实现,因此用左偏树 + 并查集
#include <bits/stdc++.h> using namespace std; const int N = 100100; struct node { int l, r, d, val; //l,r是左右儿子,d维护左偏树距离 void init(int _val) { val = _val; l = r = d = 0; } }tr ; int par , rnk ; void init(int n) { for(int i = 1; i <= n; i++) par[i] = i; } int ser(int x) { int r = x, i = x, j; while(r != par[r]) r = par[r]; while(i != r) j = par[i], par[i] = r, i = j; return r; } void unite(int x, int y) { x = ser(x), y = ser(y); if(x == y) return; par[x] = y; } int leftree_merge(int x, int y) //合并两个左偏树 { if(! x) return y; //有一个为空,则返回另一个 if(! y) return x; if(tr[x].val < tr[y].val) swap(x, y); tr[x].r = leftree_merge(tr[x].r, y); par[tr[x].r] = x; if(tr[tr[x].l].d < tr[tr[x].r].d) swap(tr[x].l, tr[x].r); //距离大的作为左儿子,小的作为右儿子 if(tr[x].r) tr[x].d = tr[tr[x].r].d + 1; //更新距离 else tr[x].d = 0; return x; } int leftree_pop(int x) { int ls = tr[x].l, rs = tr[x].r; par[ls] = ls, par[rs] = rs; tr[x].init(tr[x].val); return leftree_merge(ls, rs); } int del(int x) //这道题中每次弹出的必然是根节点,所以不会破坏左偏树性质,因此不用维护距离,于是leftree_pop和del函数作用相同 { int rx = par[x]; int ls = tr[x].l, rs = tr[x].r; par[ls] = ls, par[rs] = rs; //tr[x].l = tr[x].r = tr[x].d = 0; tr[x].init(tr[x].val); int p = leftree_merge(ls, rs); //把待删除节点的两个儿子合并 if(rx != x) //把新合并的点挂到待删除节点的父亲下面 { if(tr[rx].l == x) tr[rx].l = p; if(tr[rx].r == x) tr[rx].r = p; } x = rx; while(x != par[x]) //删除一个点后可能会破坏左偏树性质,则从下至上更新距离 { if(tr[tr[x].l].d < tr[tr[x].r].d) swap(tr[x].l, tr[x].r); if(tr[tr[x].r].d + 1 == tr[x].d) break; tr[x].d = tr[tr[x].r].d + 1; rx = par[x]; } return p; //返回其左右儿子合并后的节点 } int main() { int n, m, val; while(~ scanf("%d", &n)) { init(n); for(int i = 1; i <= n; i++) { scanf("%d", &val); tr[i].init(val); } scanf("%d", &m); int v, u; for(int i = 1; i <= m; i++) { scanf("%d%d", &v, &u); int rv = ser(v), ru = ser(u); if(rv == ru) puts("-1"); else { int rrv = leftree_pop(rv); //int rrv = del(rv); tr[rv].val /= 2; rv = leftree_merge(rrv, rv); int rru = leftree_pop(ru); //int rru = del(ru); tr[ru].val /= 2; ru = leftree_merge(rru, ru); printf("%d\n", tr[leftree_merge(rv, ru)].val); } } } return 0; }
相关文章推荐
- SpringMVC 返回String中文乱码
- Android异步消息处理机制详解及源码分析 Handler
- 【分享】WeX5的正确打开方式(7)——数据组件详解
- java.lang.String cannot be cast to [Ljava.lang.Object
- matlab计算运行时间方法
- 抓取网页中数据 -----51book中城市码
- 20160712001 SQL server R2 更名
- JDK1.5之后怎么玩转多线程(Lock和Condition的使用)
- 2016最新CocoaPods使用
- <c:if test=""></c:if>如何判断空(使用例子)
- IOS应用程序扩展Application Extension是什么(包括第三方输入法以及来电防骚扰)
- timescale的理解
- Android二级缓存之物理存储介质上的缓存DiskLruCache
- Android二级缓存之物理存储介质上的缓存DiskLruCache
- CentOS 7 安装 MySQL
- Linux虚拟地址空间布局
- 获取文件夹中所有文件的文件名
- python编码问题
- Android中的基础----如何获得LinearLayout布局的高和宽
- 自定义-弹幕