2020牛客寒假算法基础集训营4.F——树上博弈【DFS】

题目传送门


题目描述

现有一个 n 个点,n-1条边组成的树,其中 1 号点为根节点。
牛牛和牛妹在树上玩游戏,他们在游戏开始时分别在树上两个不同的节点上。
在游戏的每一轮,牛牛先走一步,而后牛妹走一步。他们只能走到没有人的空节点上。如果谁移动不了,就输掉了游戏。现在牛牛和牛妹决定随机选择他们分别的起点,于是他们想知道,有多少种游戏开始的方式,使得牛牛存在一种一定获胜的最优策略。
两种开始方式相同,当且仅当在两种开始方式中牛牛,牛妹的开始位置是分别相同的,否则开始方式就被视作不同的。


输入描述:

第一行输入为一个整数 n,代表树的点数。
第二行n-1个整数 p 2 , p 3 , , p n p_2,p_3,\ldots,p_{n} ,分别代表2,3,…,n号点的父节点编号。


输出描述:

一行一个整数,代表答案。


输入

3
1 2

2
1

30
1 1 2 1 2 1 3 2 3 4 2 3 1 2 3 4 2 4 5 6 3 4 12 12 12 13 13 13 13


输出

2

0

428


说明

  1. 当且仅当牛牛在1号点,牛妹在3号点,或者牛牛在3号点,牛妹在1号点时,牛牛才获胜。
  2. 由于无论如何牛牛都无路可走,因此必然牛妹获胜。
  3. QwQ

备注:

n 1 0 6 n \le 10^6

1 p i < i 1\le p_i < i


题解

  • 首先我们知道,如果A输掉,那么A唯一的一条边上有人,即A一定在叶子上
  • 设两个人初始距离为D,每人移动后D+1或者D-1
  • 假设最开始D为偶数,那么当牛牛移动后,D始终为偶数牛妹妹移动后,D始终为奇数
  • 已知当两人相邻的时候D=1,是奇数,也就是说,D=1的时候,开始走的人输掉。
  • 那么经过上面分析,我们就可以知道:如果最初D为偶数,牛牛获胜,反之如果最初为奇数,牛妹妹获胜。
  • 那么答案就很显然了,只需要求出深度为奇数的点和偶数的点的数量即可

注意

  • 注意到题目有一个特殊的范围: 1 p i < i 1\le p_i < i
  • 说实话这个没啥用,正解应该是跑DFS,但是由于这个条件存在,导致了任意一个点确定下来的时候,他的父节点一定在他前面确定。也就可以不用DFS了,输入的时候直接就已经知道父节点的深度了。
  • 显然这个额外条件导致数据很水

AC-Code

#include <bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
const int maxn = 1e6 + 7;

ll cnt[2]; // 当前节点为根的子树
vector<int>G[maxn];
void dfs(int now, int d) {
	for (auto v : G[now]) {
		dfs(v, d + 1);
	}
	++cnt[d & 1];
}
int main() {
	ios;
	int n;	while (cin >> n) {
        cnt[0] = cnt[1] = 0;
		for(int i = 1; i <= n; ++i)    G[i].clear();
		for (int i = 2; i <= n; ++i) {
			int fa;	cin >> fa;
			G[fa].push_back(i);
		}
		dfs(1, 0);
		cout << cnt[1] * (cnt[1] - 1) + cnt[0] * (cnt[0] - 1) << endl;
	}
	return 0;
}
/*
10
10 9 8 1 3 6 9 1 5

48
*/

/*
10
1 1 2 2 4 5 3 6 8

40
*/
发布了179 篇原创文章 · 获赞 109 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Q_1849805767/article/details/104271329