题目:K. Kingdom’s Power
题意:根节点1上有无数个军队,每一次国王都可以指挥一支军队向相邻一个节点运动,问多少次占领所有的节点。
首先可以分析出在当前节点有一支军队,那么最小的走法,仔细考虑,必然是先走的子节点深度最浅的,由于走完最浅的返回路径不需要增加过多,但是根节点上有无数个军队,需要判断就是从根节点派兵还是让走到叶子节点的兵在返回。至此可以得出贪心的策略。
写法的话,就是sort当前节点的子节点按照最深树的高度排序,找是由其他树的节点走过来的还是根节点指派,一旦是根节点指派那么往上回溯的节点一定都是根节点指派的,不然就必须更新当前的可利用的节点深度。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
//#include<unordered_map>
#include<map>
#include<algorithm>
#include<queue>
#define mmp make_pair
#define inf 0x3f3f3f3f
#define llinf 0x7fffffffffffffff
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
typedef double ld;
vector<int>hh[1000100];
int high[1000100];
ll ans=0;
ll dp[1000100];
struct cmp1{
bool operator()(PP x,PP y)
{
return x.first>y.first;//小的优先级高 ,从小到大排
}
};
priority_queue <PP,vector<PP>,cmp1 > que[1000100];
void dfshigh(int u,int f) {
high[u]=high[f]+1;
dp[u]=0;
if(hh[u].size()==1 && hh[u][0]==f) {
return ;
}
for(int i=0;i<hh[u].size();++i) {
int v=hh[u][i];
if(v==f) continue;
dfshigh(v,u);
dp[u]=max(dp[u],dp[v]+1);
que[u].push(mmp(dp[v],v));
}
}
int dfs(int u,int f,int step) {
while(!que[u].empty()) {
PP temp=que[u].top();
que[u].pop();
step=dfs(temp.second,u,step+1)+1;
}
if(hh[u].size()==1 && hh[u][0]==f ) {
ans+=min(high[u],step);
return 0;
}
return step;
}
int main() {
int T;
scanf("%d",&T);
int cases=1;
while(T--) {
int n;
scanf("%d",&n);
for(int i=0;i<=n;++i) {
while(!que[i].empty()) {
que[i].pop();
}
high[i]=dp[i]=0;
hh[i].clear();
}
for(int i=2;i<=n;++i) {
int x; scanf("%d",&x);
hh[i].push_back(x);
hh[x].push_back(i);
}
high[0]=-1;
dfshigh(1,0);
ans=0;
dfs(1,0,0);
printf("Case #%d: %lld\n",cases++,ans);
}
return 0;
}