P8347-「Wdoi-6」另一侧的月【博弈论,结论】
正题
题目链接:https://www.luogu.com.cn/problem/P8347
题目大意
给出一棵树,两个人轮流操作。
操作者可以选择一个点删除,然后选择一个剩下的连通块,删除其他连通块。
操作完成后只剩下一个点的人失败,求是否先手必败。
\(1\leq T\leq 5,1\leq n\leq 10^5\)
解题思路
考虑如果存在某个子树是先手必败的,那么可以直接选择删这个点的父亲,然后选择这个子树,就先手必胜了。
所以如果先手必败那么肯定除了根节点以外所有点的子树都是先手必胜的。
然后此时考虑根节点的胜负情况,那么每次操作的人肯定都会选择根节点的一个儿子的子树删除,因为如果不这么做肯定会被另一个人偷鸡。
所以此时根节点的胜负取决于他儿子个数的奇偶性。
那么我们可以用同样的方法算出每个节点子树的胜负就可以了。
时间复杂度:\(O(Tn)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node{
int to,next;
}a[N<<1];
int T,n,tot,ans,ls[N];
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void dfs(int x,int fa){
int sum=0;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
dfs(y,x);sum++;
}
if(x!=1)ans|=(sum&1);
else ans|=!(sum&1);
return;
}
int main()
{
scanf("%d",&T);
while(T--){
memset(ls,0,sizeof(ls));
scanf("%d",&n);tot=ans=0;
for(int i=1,x,y;i<n;i++){
scanf("%d%d",&x,&y);
addl(x,y);addl(y,x);
}
dfs(1,0);
if(ans)puts("Hifuu");
else puts("Luna");
}
return 0;
}