题意:
n堆数字 m个操作 操作是两个人轮流执行 有5种操作 T操作拿一堆数字 C操作两个人比较自己手中最大的数字胜者得到对方的数字 L操作扔掉最大数字 A操作使最大数字加上一个值 E操作是最大数字改变值 两个人按上述规则进行R轮游戏 问每局游戏的比分和最后谁赢
思路:
要么是合并一堆数字 要么从一堆数字里拿最大 很明显这时可并堆的操作 想到使用左偏树
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 2001000 int R,happy,wolf,n,m,tot; int f[110],root[2],sum[110]; struct node { int v,l,r,dis; }nd[N]; int newnode(int x) { nd[tot].v=x; nd[tot].l=0; nd[tot].r=0; nd[tot].dis=0; tot++; return tot-1; } int merge(int x,int y) { if(!x) return y; if(!y) return x; if(nd[x].v<nd[y].v) swap(x,y); nd[x].r=merge(nd[x].r,y); if(nd[nd[x].l].dis<nd[nd[x].r].dis) swap(nd[x].l,nd[x].r); nd[x].dis=nd[nd[x].r].dis+1; return x; } int pop(int x) { int tmp=merge(nd[x].l,nd[x].r); nd[x].dis=nd[x].l=nd[x].r=0; return tmp; } int main() { int i,j,k,num; char op[10]; while(~scanf("%d",&R)) { happy=wolf=0; while(R--) { scanf("%d%d",&n,&m); tot=1; memset(f,0,sizeof(f)); memset(sum,0,sizeof(sum)); root[0]=root[1]=0; for(i=1;i<=m;i++) scanf("%d",&sum[i]); for(i=1;i<=m;i++) { for(j=1;j<=sum[i];j++) { scanf("%d",&num); f[i]=merge(f[i],newnode(num)); } } for(i=1;i<=n;i++) { scanf("%s",op); if(op[0]=='T') { scanf("%d",&k); root[1&i]=merge(root[1&i],f[k]); f[k]=0; sum[(1&i)+105]+=sum[k]; } else if(op[0]=='C') { if(nd[root[0]].v>nd[root[1]].v) { root[0]=merge(root[0],root[1]); sum[105]+=sum[106]; root[1]=0; sum[106]=0; } else if(nd[root[0]].v<nd[root[1]].v) { root[1]=merge(root[0],root[1]); sum[106]+=sum[105]; root[0]=0; sum[105]=0; } } else if(op[0]=='L') { root[1&i]=pop(root[1&i]); sum[(1&i)+105]--; } else if(op[0]=='A') { scanf("%d",&k); nd[root[1&i]].v+=k; } else if(op[0]=='E') { scanf("%d",&k); root[1&i]=pop(root[1&i]); root[1&i]=merge(root[1&i],newnode(k)); } } if(sum[105]>sum[106]) happy++; else wolf++; printf("%d:%d\n",sum[106],sum[105]); } if(happy>wolf) puts("I will be back!!"); else puts("Hahaha...I win!!"); } return 0; }
时间: 2024-10-17 01:02:17