ZOJ 2334 Monkey King

来源:互联网 发布:十进制转bcd码算法 编辑:程序博客网 时间:2024/05/21 08:57

题目大意:

        在一个森林里曾经有一群猴子(总共有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#defineMAXMONKEYN100001struct BNode;//Body of Node,左偏树结点typedefstruct BNodeNode;typedefstruct BNode *Tree;structBNode {intkey;//强悍值intnpl;//nil path length,      //零路径长度,即当前结点到最近      //叶子结点的距离(按边的数量算)Treelft;Treerht;};intset[MAXMONKEYN];//并查集集合Nodenod[MAXMONKEYN];//node,存放左偏树的各个结点Treemok[MAXMONKEYN];//monkey,最开始每个猴子所代表的结点都是                 //一棵树的树根TreeMerge( Tree t1, Tree t2 ) {//左偏树经典操作,合并两颗左偏树//也是堆的合并的经典操作if ( !t1 )return t2;if ( !t2 )return t1;TreeMg_to_R( Tree t1, Tree t2 );//Merge to right child                     //将t2和t1的右子树进行合并//保持树顶一定是最大值if ( t1->key > t2->key )return Mg_to_R( t1, t2 );elsereturn Mg_to_R( t2, t1 );}voidSwapCld(Tree tree) {//swap child    //将tree的两个子树进行交换Treettmp;ttmp= tree->lft;tree->lft= tree->rht;tree->rht= ttmp;}TreeMg_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;}TreeAdjst(Tree tree) {//Adjust,对两颗准备决斗的树    //在决斗之后进行调整//主要任务就是模拟决斗发生之后,树顶(最强悍猴子)//的强悍值减半,并挪去,将左右子树合并后再将踢出的//原树顶结点重新加入该树(其实也是合并操作)Treetmax;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 );}intfind(int x) {if ( x == set[x] )return x;return set[x] = find( set[x] );}intmain() {intnm;//number of monkeysintnq;//number of quarrelsinti;//计数变量intu, v;//发生争斗的两个猴子的编号intsu, 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>#defineMAXMONKEYN100001struct BNode;typedefstruct BNodeNode;typedefstruct BNode *Tree;structBNode {intkey;intnpl;Treelft;Treerht;};intset[MAXMONKEYN];Nodenod[MAXMONKEYN];Treemok[MAXMONKEYN];TreeMerge( Tree t1, Tree t2 ) {if ( !t1 )return t2;if ( !t2 )return t1;TreeMg_to_R( Tree t1, Tree t2 );if ( t1->key > t2->key )return Mg_to_R( t1, t2 );elsereturn Mg_to_R( t2, t1 );}voidSwapCld(Tree tree) {Treettmp;ttmp= tree->lft;tree->lft= tree->rht;tree->rht= ttmp;}TreeMg_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;}TreeAdjst(Tree tree) {Treetmax;tmax= tree;tree= Merge( tree->lft, tree->rht );tmax->key>>= 1;tmax->npl=0;tmax->lft= NULL;tmax->rht= NULL;return Merge( tmax, tree );}intfind(int x) {if ( x == set[x] )return x;return set[x] = find( set[x] );}intmain() {intnm;intnq;inti;intu, v;intsu, 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, 减少

0 0
原创粉丝点击