题目描述
现有一个 n 个点,n-1条边组成的树,其中 1 号点为根节点。
牛牛和牛妹在树上玩游戏,他们在游戏开始时分别在树上两个不同的节点上。
在游戏的每一轮,牛牛先走一步,而后牛妹走一步。他们只能走到没有人的空节点上。如果谁移动不了,就输掉了游戏。现在牛牛和牛妹决定随机选择他们分别的起点,于是他们想知道,有多少种游戏开始的方式,使得牛牛存在一种一定获胜的最优策略。
两种开始方式相同,当且仅当在两种开始方式中牛牛,牛妹的开始位置是分别相同的,否则开始方式就被视作不同的。
输入描述:
第一行输入为一个整数 n,代表树的点数。
第二行n-1个整数$ p_2,p_3,...,p_n $
,分别代表2,3,...,n号点的父节点编号。
$ n\leq 10^6,1 \leq p_i< i. $
输出描述:
一行一个整数,代表答案。
输入
3 1 2
输出
2
说明
当且仅当牛牛在1号点,牛妹在3号点,或者牛牛在3号点,牛妹在1号点时,牛牛才获胜。
传送门:
https://ac.nowcoder.com/acm/contest/3005/F
思路:
首先自己输掉的唯一方法是自己在叶节点,而另一个人在该叶节点的父节点上。
此时两人的距离D为奇数。
两人的距离D为奇数时,A先走使得两个人的距离D减小(也就是往根节点走)。
B也可以采取同样的策略使得两人的距离D减小,最后会到两人的距离为1,该A走。
此时A只能往叶节点走,B只要跟着A往叶节点走就能获胜。
偶数的情况同理。
所以该题只要计算一下每个结点的深度即可。
代码:
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 1e6 + 10; 6 7 struct node 8 { 9 int nxt; 10 int to; 11 }; 12 13 node t[N]; 14 int head[N]; 15 bool vis[N]; 16 int d[N]; 17 18 int tot; 19 void addedges(int u, int v) 20 { 21 t[++tot].to = v; 22 t[tot].nxt = head[u]; 23 head[u] = tot; 24 } 25 void dfs(int x) 26 { 27 vis[x] = true; 28 29 for(int i = head[x]; i; i = t[i].nxt) 30 { 31 int y = t[i].to; 32 if(!vis[y]) 33 { 34 d[y] = d[x] + 1; 35 dfs(y); 36 } 37 } 38 } 39 int main() 40 41 { 42 int n; 43 scanf("%d", &n); 44 for(int i = 2; i <= n; i++) 45 { 46 int x; 47 scanf("%d", &x); 48 addedges(x, i); 49 } 50 dfs(1); 51 52 long long a = 0; 53 long long b = 0; 54 for(int i = 1; i <= n; i++) 55 { 56 if(d[i] % 2) 57 a++; 58 else 59 b++; 60 } 61 printf("%lld\n", (a - 1)*a + (b - 1)*b ); 62 }