题意
在根节点1处你拥有无限兵力,每次你可以操控你的兵团移动1,移动到一个节点则占领该节点。输出最少多少步占领全部。
思路
1.首先一个节点,可以是从兄弟树派过来的,也可以是从根节点重新派过来,要比较两者之间的距离
2.如果是从兄弟树过来,记录以每个节点为祖先的最深深度,最深的一条链一定是最后遍历走一遍,别的走两遍;如果是从根节点,则加上深度即可。
3.记录每个节点深度用以判断距离大小。
Ac Code
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
#define enl , writestr("\n")
#define int long long
#define endl "\n"
#define PII pair<int, int>
#define ULL unsigned long long
#define xx first
#define yy second
#define PI acos(-1)
const int P = 131;//131,13331
const int N = 2e6 + 10;
const int M = 1e3 + 10;
const int INF = 1e18;
const int ENF = -1e18;
const int mod = 1e9 + 7;//998244353
const int modd = 998244353;
void ClearFloat() { ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); }int read() { int ret = 0, f = 1; char ch = getchar(); while ('0' > ch || ch > '9') { if (ch == '-')f = -1; ch = getchar(); }while ('0' <= ch && ch <= '9') { ret = ret * 10 + ch - '0'; ch = getchar(); }return ret * f; }void write(int x) { char num[30]; int cnt = 0; if (x == 0) { putchar('0'); return; }if (x < 0) { putchar('-'); x = -x; }while (x > 0) { num[cnt++] = x % 10 + '0'; x /= 10; }while (cnt > 0) { putchar(num[--cnt]); } }double readdou() { double x = 0; int flag = 0; char ch = 0; while (!isdigit(ch)) { flag |= (ch == '-'); ch = getchar(); } while (isdigit(ch)) { x = x * 10 + (ch - '0'); ch = getchar(); }if (ch != '.') return flag ? -x : x; int f = 1; ch = getchar(); while (isdigit(ch)) { x = x + (ch - '0') * pow(10, -f); f++; ch = getchar(); }return flag ? -x : x; }void wridou(int x) { char num[30]; int cnt = 0; if (x == 0) { putchar('0'); return; }if (x < 0) { putchar('-'); x = -x; }while (x > 0) { num[cnt++] = x % 10 + '0'; x /= 10; }while (cnt > 0) { putchar(num[--cnt]); } }int gcd(int a, int b) { if (b) while ((a %= b) && (b %= a)); return a + b; }int lcm(int a, int b) { return a * b / gcd(a, b); }
int e[N], ne[N], idx, h[N], n, m, t, d[N], ma[N], ans, pre;
vector<int>vt[N];
bool cmp(int a, int b)
{
return ma[a] < ma[b];
}
void dfs_sort(int u, int de)//占领顺序按照排序后的节点进行dfs即可
{
d[u] = ma[u] = de;
for (auto v : vt[u])
{
dfs_sort(v, de + 1);
ma[u] = max(ma[u], ma[v]);//记录每个节点为祖先的最深链
}
sort(vt[u].begin(), vt[u].end(), cmp);//按深度从小到大排序
}
void dfs_ans(int u, int fa)
{
if (u != 1)
{
if (!pre) ans += d[u];//如果还未排除军团则输出深度
else
{
if (d[pre] - d[fa] + 1 <= d[fa]) //如果是从兄弟树过来,或者是从其父节点过来
ans += d[pre] - d[fa] + 1;
else //如果是重新派一路
ans += d[u];
}
pre = u;
}
for (auto v : vt[u]) dfs_ans(v, u);
}
signed main()
{
t = read(); int _ = 1;
memset(h, -1, sizeof h);
while (t--)
{
cin >> n;
for (int i = 0; i <= n; i++) vt[i].clear(), d[i] = 0, ma[i] = 0;
for (int i = 2; i <= n; i++)
{
int u; u = read();
vt[u].push_back(i);
}
dfs_sort(1, 0);
ans = 0, pre = 0;
dfs_ans(1, -1);
printf("Case #%lld: %lld\n", _, ans);
_++;
}
}