ZOJ 2334 Monkey King
2014-03-01 23:59
267 查看
题目大意:
在一个森林里曾经有一群猴子(总共有N只,N ≤ 100,000),一开始它们各干各的,互不相识,但是猴子数量多不可避免地会发生冲突,这些冲突只会发生在互不相识的两个猴子之间。当冲突发生时,两只猴子各自都会招来自己最强悍的朋友来一场决斗(如果发生冲突的猴子本身就是自己朋友圈中最强悍的,则它会直接自己上),假设每个猴子都有一个强悍值(题中会指定各个猴子的强悍值),决斗之后,两只猴子的强悍值都降为原来的一半,并且双方的朋友也都相互结交成了朋友组成了一个更大的朋友圈。
现有多个测例(测例数量无上限),每个测例中都会先给出猴子数量N(并赋予每个猴子一定的强悍值)和冲突数量M,对于每次冲突都会给出发生冲突的两个猴子的编号,如果两个猴子是相识的则输出-1,否则输出冲突后当事人圈子(合并后)的最强悍猴子的强悍值。
题目链接
注释代码:
无注释代码:
单词解释:
aggressive:adj, 侵略性的,好斗的
quarrel:vt, 吵架,争论
duel:vi/n, 决斗
conflict:vt/n, 冲突,争斗
reduce:vt, 减少
在一个森林里曾经有一群猴子(总共有N只,N ≤ 100,000),一开始它们各干各的,互不相识,但是猴子数量多不可避免地会发生冲突,这些冲突只会发生在互不相识的两个猴子之间。当冲突发生时,两只猴子各自都会招来自己最强悍的朋友来一场决斗(如果发生冲突的猴子本身就是自己朋友圈中最强悍的,则它会直接自己上),假设每个猴子都有一个强悍值(题中会指定各个猴子的强悍值),决斗之后,两只猴子的强悍值都降为原来的一半,并且双方的朋友也都相互结交成了朋友组成了一个更大的朋友圈。
现有多个测例(测例数量无上限),每个测例中都会先给出猴子数量N(并赋予每个猴子一定的强悍值)和冲突数量M,对于每次冲突都会给出发生冲突的两个猴子的编号,如果两个猴子是相识的则输出-1,否则输出冲突后当事人圈子(合并后)的最强悍猴子的强悍值。
题目链接
注释代码:
/* * Problem ID : ZOJ 2334 Monkey King * Author : Lirx.t.Una * Language : C * Run Time : 380 ms * Run Memory : 3684 KB */ #include <string.h> #include <stdio.h> //maximum number of monkeys //猴子的最大数量 //100,000 + 1 //数组下标可以取到1-100,000 #define MAXMONKEYN 100001 struct BNode;//Body of Node,左偏树结点 typedef struct BNode Node; typedef struct BNode * Tree; struct BNode { int key;//强悍值 int npl;//nil path length, //零路径长度,即当前结点到最近 //叶子结点的距离(按边的数量算) Tree lft; Tree rht; }; int set[MAXMONKEYN];//并查集集合 Node nod[MAXMONKEYN];//node,存放左偏树的各个结点 Tree mok[MAXMONKEYN];//monkey,最开始每个猴子所代表的结点都是 //一棵树的树根 Tree Merge( Tree t1, Tree t2 ) {//左偏树经典操作,合并两颗左偏树 //也是堆的合并的经典操作 if ( !t1 ) return t2; if ( !t2 ) return t1; Tree Mg_to_R( Tree t1, Tree t2 );//Merge to right child //将t2和t1的右子树进行合并 //保持树顶一定是最大值 if ( t1->key > t2->key ) return Mg_to_R( t1, t2 ); else return Mg_to_R( t2, t1 ); } void SwapCld(Tree tree) {//swap child //将tree的两个子树进行交换 Tree ttmp; ttmp = tree->lft; tree->lft = tree->rht; tree->rht = ttmp; } Tree Mg_to_R( Tree t1, Tree t2 ) { //左偏树必须是左子树的npl长≥右子树的 //因此当左子树为空的时候可以直接将t2接在 //t1的左子树上 if ( !t1->lft ) t1->lft = t2; else { //否则先跟t1右子树合并(因为右子树比较短) //这样可以使整棵树趋于平衡 t1->rht = Merge( t1->rht, t2 ); //但如果过头了(即右子树偏大) //则需要交换两个子树了 if ( t1->rht->npl > t1->lft->npl ) SwapCld(t1); //由于左子树永远长于右子树 //因此零路径长只与右子树有关 //在右子树的npl上加1即可更新 t1->npl = t1->rht->npl + 1; } return t1; } Tree Adjst(Tree tree) {//Adjust,对两颗准备决斗的树 //在决斗之后进行调整 //主要任务就是模拟决斗发生之后,树顶(最强悍猴子) //的强悍值减半,并挪去,将左右子树合并后再将踢出的 //原树顶结点重新加入该树(其实也是合并操作) Tree tmax; tmax = tree; tree = Merge( tree->lft, tree->rht ); //被踢出后需要对其npl以及左右链域进行及时清空 //否则会导致内存崩溃引发段错误而吐核 tmax->key >>= 1; tmax->npl = 0; tmax->lft = NULL; tmax->rht = NULL; return Merge( tmax, tree ); } int find(int x) { if ( x == set[x] ) return x; return set[x] = find( set[x] ); } int main() { int nm;//number of monkeys int nq;//number of quarrels int i;//计数变量 int u, v;//发生争斗的两个猴子的编号 int su, sv;//set of u and v,求u、v所在的集合 while ( ~scanf("%d", &nm) ) { //每个测例开始时的初始化 for ( i = 1; i <= nm; i++ ) set[i] = i; memset( nod + 1, 0, nm * sizeof(Node)); //输入 for ( i = 1; i <= nm; i++ ) { scanf("%d", &nod[i].key); mok[i] = nod + i; } scanf("%d", &nq); while ( nq-- ) { scanf("%d%d", &u, &v); su = find(u); sv = find(v); if ( su == sv ) { puts("-1"); continue; } mok[su] = Adjst( mok[su] ); mok[sv] = Adjst( mok[sv] ); //由于合并后的树存于sv中 //所以相对应的并查集合并也必须将集合合并在sv中 //否则在下次find的时候找的结点不是左偏树的树顶 mok[sv] = Merge( mok[su], mok[sv] ); set[su] = sv; printf("%d\n", mok[sv]->key); } } return 0; }
无注释代码:
#include <string.h> #include <stdio.h> #define MAXMONKEYN 100001 struct BNode; typedef struct BNode Node; typedef struct BNode * Tree; struct BNode { int key; int npl; Tree lft; Tree rht; }; int set[MAXMONKEYN]; Node nod[MAXMONKEYN]; Tree mok[MAXMONKEYN]; Tree Merge( Tree t1, Tree t2 ) { if ( !t1 ) return t2; if ( !t2 ) return t1; Tree Mg_to_R( Tree t1, Tree t2 ); if ( t1->key > t2->key ) return Mg_to_R( t1, t2 ); else return Mg_to_R( t2, t1 ); } void SwapCld(Tree tree) { Tree ttmp; ttmp = tree->lft; tree->lft = tree->rht; tree->rht = ttmp; } Tree Mg_to_R( Tree t1, Tree t2 ) { if ( !t1->lft ) t1->lft = t2; else { t1->rht = Merge( t1->rht, t2 ); if ( t1->rht->npl > t1->lft->npl ) SwapCld(t1); t1->npl = t1->rht->npl + 1; } return t1; } Tree Adjst(Tree tree) { Tree tmax; tmax = tree; tree = Merge( tree->lft, tree->rht ); tmax->key >>= 1; tmax->npl = 0; tmax->lft = NULL; tmax->rht = NULL; return Merge( tmax, tree ); } int find(int x) { if ( x == set[x] ) return x; return set[x] = find( set[x] ); } int main() { int nm; int nq; int i; int u, v; int su, sv; while ( ~scanf("%d", &nm) ) { for ( i = 1; i <= nm; i++ ) set[i] = i; memset( nod + 1, 0, nm * sizeof(Node)); for ( i = 1; i <= nm; i++ ) { scanf("%d", &nod[i].key); mok[i] = nod + i; } scanf("%d", &nq); while ( nq-- ) { scanf("%d%d", &u, &v); su = find(u); sv = find(v); if ( su == sv ) { puts("-1"); continue; } mok[su] = Adjst( mok[su] ); mok[sv] = Adjst( mok[sv] ); mok[sv] = Merge( mok[su], mok[sv] ); set[su] = sv; printf("%d\n", mok[sv]->key); } } return 0; }
单词解释:
aggressive:adj, 侵略性的,好斗的
quarrel:vt, 吵架,争论
duel:vi/n, 决斗
conflict:vt/n, 冲突,争斗
reduce:vt, 减少
相关文章推荐
- ZOJ 2334(Monkey King-左偏树第一题)
- ZOJ2334 HDU1512 Monkey King,左偏树
- 【左偏树】【ZOJ 2334】Monkey King
- zoj 2334 Monkey King 左偏树+并查集
- zoj 2334 Monkey King(左偏树+并查集)
- ZOJ 2334 Monkey King
- zoj 2334 Monkey King
- ZOJ2334-Monkey King【二项堆】
- ZOJ 2334 Monkey King(左偏树)
- 【ZOJ2334】Monkey King
- ZOJ 2334 Monkey King 可并堆左偏树
- ZOJ 2334 HDU 1512 Monkey King
- ZOJ 2334 Monkey King 可并堆左偏树
- zoj2334 Monkey King , 并查集,可并堆,左偏树
- ZOJ 2334 Monkey King
- ZOJ 2334 Monkey King(左偏树)
- zoj 2334 Monkey King
- ZOJ 2334(Monkey King-左偏树第一题)
- 【zoj2334】【左偏树】Monkey King
- zoj2334 Monkey King , 并查集,可并堆,左偏树