[atAGC017D]Game on Tree

将其1为根建树,操作显然即去掉一棵子树(非本身)

考虑sg函数,定义$sg(T)$为有根树$T$的sg值,则有以下结论——

结论:令$T'$为$T$的根节点新增一个父亲得到的树,则$sg(T')=sg(T)+1$

假设去掉$T$任意一棵子树(非本身)后会得到$T_{1},T_{2},...,T_{k}$,$T'_{i}$为$T_{i}$的根节点新增一个父亲得到的树,那么$T'$去掉任意一棵子树(非本身)后即会得到$T'_{1},T'_{2},...,T'_{k}$和"一个节点"的树

显然"一个节点"的树的$sg$值为0,因此$sg(T')=mex(\{sg(T'_{i}),0\})$

考虑归纳,并代入$sg(T'_{i})=sg(T_{i})+1$,不难得到$sg(T')=sg(T)+1$,即得证

进一步的,考虑$T$根节点儿子的子树依次为$T_{1},T_{2},...,T_{k}$,显然对$T_{i}$再加上$T$根节点即是一个独立的问题,结合sg函数的性质和结论,也即$sg(T)=\bigoplus_{i=1}^{k}(sg(T_{i})+1)$,再树形dp即可

时间复杂度为$o(n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 vector<int>v[N];
 5 int n,x,y,sg[N];
 6 void dfs(int k,int fa){
 7     for(int i=0;i<v[k].size();i++)
 8         if (v[k][i]!=fa){
 9             dfs(v[k][i],k);
10             sg[k]^=sg[v[k][i]]+1;
11         }
12 }
13 int main(){
14     scanf("%d",&n);
15     for(int i=1;i<n;i++){
16         scanf("%d%d",&x,&y);
17         v[x].push_back(y);
18         v[y].push_back(x);
19     }
20     dfs(1,0);
21     if (sg[1])printf("Alice\n");
22     else printf("Bob\n");
23     return 0;
24 }
View Code

 

posted @ 2021-12-02 15:02  PYWBKTDA  阅读(77)  评论(0编辑  收藏  举报