HDU3031 To Be Or Not To Be 左偏树 可并堆

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - HDU3031


题意概括

  喜羊羊和灰太狼要比赛。

  有R次比赛。

  对于每次比赛,首先输入n,m,n表示喜羊羊和灰太狼的这次比赛回合数,m表示一开始有m堆数字。

  然后输入m个数,第i个(p[i])表示第i堆里面有多少个数。

  接下来的m行,第i行有p[i]个数,分别表示第i堆数有哪些。

  然后n回合,灰太狼和喜羊羊大战。

  两人轮流操作,灰太狼先。

  1) T K: 拿到第 k 堆所有数字

  2) C:    喜羊羊和灰太狼手中最大的数字进行比较,赢得一方可以把对方的所有数字全部取过来。(牌数如果相同就什么也不干)

  3) L:     失去手中最大的数字

  4) A P: 手中最大的数字加上P

  5) E Q: 手中最大的数字改为Q

  然后,每次比赛结束,输出“灰太狼手中数字个数 : 喜羊羊手中数字个数”

  所有比赛结束之后,统计灰太狼和喜羊羊赢的次数。

  如果灰太狼的次数>=喜羊羊的次数,那么输出"Hahaha...I win!!"

  否则输出"I will be back!!"


 

题解

  这题就是题意比较难理解。

  几乎是裸的可并堆,左偏树一发就可以了。

  应该不需要解释吧。

  不会的自己去看左偏树。


 

代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
const int M=105,N=M*10000;
int Case,n,m,p[M],root[M],v1=0,v0=0;
int ls[N],rs[N],npl[N],val[N],cnt;
void makeheap(int x,int v){
	ls[x]=rs[x]=npl[x]=0;
	val[x]=v;
}
int merge(int a,int b){
	if (!a||!b)
		return a+b;
	if (val[a]<val[b])
		swap(a,b);
	rs[a]=merge(rs[a],b);
	if (npl[rs[a]]>npl[ls[a]])
		swap(rs[a],ls[a]);
	npl[a]=npl[rs[a]]+1;
	return a;
}
void pop(int &rt){
	rt=merge(ls[rt],rs[rt]);
}
void change(int &rt,int v){
	int x=merge(ls[rt],rs[rt]);
	makeheap(rt,v);
	rt=merge(rt,x);
}
int main(){
	scanf("%d",&Case);
	while (Case--){
		cnt=0;
		scanf("%d%d",&n,&m);
		for (int i=1;i<=m;i++)
			scanf("%d",&p[i]);
		memset(root,0,sizeof root);
		for (int i=1;i<=m;i++)
			for (int j=1,x;j<=p[i];j++){
				scanf("%d",&x);
				makeheap(++cnt,x);
				root[i]=merge(root[i],cnt);
			}
		int x[2],rt[2];
		memset(rt,0,sizeof rt);
		memset(x,0,sizeof x);
		for (int i=1;i<=n;i++){
			char op[2];
			int a;
			scanf("%s",op);
			if (op[0]=='T'){
				scanf("%d",&a);
				rt[i&1]=merge(rt[i&1],root[a]);
				x[i&1]+=p[a];
			}
			if (op[0]=='C'){
				if (val[rt[0]]==val[rt[1]])
					continue;
				if (val[rt[0]]>val[rt[1]]){
					x[0]+=x[1];
					x[1]=0;
					rt[0]=merge(rt[0],rt[1]);
					rt[1]=0;
				}
				else {
					x[1]+=x[0];
					x[0]=0;
					rt[1]=merge(rt[1],rt[0]);
					rt[0]=0;
				}
			}
			if (op[0]=='L'){
				pop(rt[i&1]);
				x[i&1]--;
			}
			if (op[0]=='A'){
				scanf("%d",&a);
				change(rt[i&1],val[rt[i&1]]+a);
			}
			if (op[0]=='E'){
				scanf("%d",&a);
				change(rt[i&1],a);
			}
		}
		printf("%d:%d\n",x[1],x[0]);
		if (x[1]>=x[0])
			v1++;
		else
			v0++;
	}
	puts(v1<v0?"I will be back!!":"Hahaha...I win!!");
	return 0;
}

  

posted @ 2017-12-17 20:52  zzd233  阅读(253)  评论(0编辑  收藏  举报