您的位置:首页 > 其它

ZOJ 2334 Monkey King

2014-03-01 23:59 267 查看
题目大意:

在一个森林里曾经有一群猴子(总共有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, 减少
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: