D. 学姐逗学弟 2014新生暑假个人排位赛02
时间限制 3000 ms
内存限制 131072 KB
题目描述
学弟们来了之后,学姐每天都非常高兴的和学弟一起玩耍。这一天,学姐想出了这样一个游戏,她画了一棵树,树上共有 n 个节点,现在学姐把 m(m≤n) 个石子随机放在节点上,每个节点可以放多个,每一次操作是指把每一个节点上的所有石子都往下移动到他某一个子节点(一个节点有多个石子可以分别移动到不同子节点),如果没有子节点则不移动,无法移动的人输。 学姐说,学弟是绅士应该让学姐先走,其实学姐已经策划好了自己一定会赢,但是这时学弟说,学姐先下那么我来画树和放石子吧,学姐惊呆了。现在她来想知道在新的图上,两人都按最优方案走,自己还能不能赢。
输入格式
输入第一行为一个整数 T 表示数据组数,接下来 T 组数据,每组开头为两个整数 n,m ,表示节点个数和石子个数, 1≤m≤n≤100000 ,接下来一行 n−1 个整数,表示2到 n 节点的父亲节点编号,接下来一行m个整数,表示每一个石子的位置。数据保证1为根节点。
输出格式
如果学姐能胜利,输出"MengMengDa!",否则输出"So sad..."。没有引号。
输入样例
1
3 1
1 1
1
输出样例
MengMengDa!
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define maxn 100005
#define LOCAL
using namespace std;
int n,m,cnt;
struct edge
{
int to,next;
}e[maxn];
int h[maxn],num[maxn],sg[maxn],heap[maxn],height[maxn];
void Addedge(int x,int y)
{
cnt++;e[cnt].to=y;e[cnt].next=h[x];h[x]=cnt;
}
void heapup()
{
int i,t;
i=heap[0];
while(i>1&&heap[i]<heap[i/2]){swap(heap[i],heap[i/2]);i/=2;}
}
void heapdown()
{
int i=1,j;
while(i*2<=heap[0])
{
if(i*2==heap[0]||heap[i*2]<heap[i*2+1])j=i*2;
else j=i*2+1;
if(heap[i]>heap[j]){swap(heap[i],heap[j]);i=j;}
else break;
}
}
void SetHeap(int c)
{
heap[0]++;heap[heap[0]]=c;heapup();
}
void CalSg(int x)
{
//cout<<x<<endl;
heap[0]=0;//printf("sg[%d]=%d\n",x,sg[x]);
//int i=h[4];
//for(int i=1;i<=cnt;i++)cout<<e[i].to<<' '<<e[i].next<<endl;
/*cout<<e[i].to<<endl;
i=e[i].next;
cout<<e[i].to<<endl;*/
//cout<<
//for(int i=1;i<=n;i++)cout<<h[i]<<' ';
for(int i=h[x];i!=-1;i=e[i].next)
{
//cout<<i<<endl;system("pause");
//printf("yes\n");
int to=e[i].to;
//cout<<i<<endl;system("pause");
SetHeap(sg[to]);
}
if(heap[1]>=1)sg[x]=0;
else
{
while(heap[0]>0)
{
int temp=heap[1];
heap[1]=heap[heap[0]];heap[0]--;
heapdown();
if(heap[1]!=temp+1){sg[x]=temp+1;return;}
}
}
}
void dfs(int x)
{
int cnt=0;
//cout<<x<<endl;
for(int i=h[x];i!=-1;i=e[i].next)
{
int to=e[i].to;//cout<<to<<' ';
dfs(to);
cnt++;
if(height[to]%2==0)
{
height[x]=max(height[x],height[to]);
}
//if(x==7)cout<<to<<endl;
}
//if(x==7)cout<<height[x]<<endl;
if(cnt!=0&&height[x]==-1)
for(int i=h[x];i!=-1;i=e[i].next)
{
int to=e[i].to;//cout<<to<<' ';
if(height[x]==-1&&height[to]%2==1)height[x]=height[to];
else if(height[to]%2==1)height[x]=min(height[x],height[to]);
}
height[x]++;
//cout<<endl;
//cout<<x<<' '<<cnt<<endl;
if(cnt==0){sg[x]=0;height[x]=0;}
else CalSg(x);
}
void solve()
{
int x;
scanf("%d",&x);
int maxx=x;
for(int i=2;i<=m;i++){scanf("%d",&x);if(height[x]>height[maxx])maxx=x;}
if(sg[maxx]==0)printf("So sad...\n");
else printf("MengMengDa!\n");
}
int main()
{
#ifdef LOCAL
freopen("input.txt","r",stdin);
#endif
int T;
scanf("%d",&T);
while(T--)
{
memset(h,-1,sizeof(h));
memset(num,0,sizeof(num));
memset(height,-1,sizeof(height));
//memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);//cout<<n<<' '<<m<<endl;
cnt=0;
for(int i=2;i<=n;i++)
{
int fa;
scanf("%d",&fa);
//cout<<fa<<' '<<i<<endl;
Addedge(fa,i);
}
//for(int i=1;i<=cnt;i++)cout<<e[i].to<<' '<<e[i].next<<endl;
//cout<<cnt<<endl;
/*int i=h[4];
cout<<e[i].to<<' '<<endl;
i=e[i].next;
cout<<e[i].to<<' '<<endl;
i=e[i].next;
cout<<i<<endl;*/
dfs(1);
//for(int i=1;i<=n;i++)cout<<height[i]<<' ';cout<<endl;
//for(int i=1;i<=n;i++)cout<<sg[i]<<' ';cout<<endl;
solve();
}
return 0;
}