题目大意:
在一个森林里曾经有一群猴子(总共有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, 减少