K. Kingdom‘s Power

题意

在根节点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);
		_++;
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值