树上贪心_2020qhdK

/*
 * @Author: mafengfa
 * @Date: 2022-07-16 10:16:57
 * @LastEditTime: 2022-07-16 11:03:15
 * @FilePath: \贪心\树上贪心_2020qhdK.cpp
 */
#include<bits/stdc++.h>
using namespace std;



//方法2:首先可以发现性质1一支军队必然走到叶子,否则一定不是最优。 --->   除去从根的链,其余边个数乘以2 + 所有链的长度就是答案。
//有了这个性质,问题被大大简化,但是会发现仍难以下手,然后发现性质2.对于原树来说,深度最深的点到根必然为链,在此简单证明一下,如果不是,则发生链的转移一定更优,进而矛盾,证毕。
//当然这个在这没啥用啊,就是提一嘴,我们发现对于子树,有两种借军队的方法,要么从之前的叶子借,要么从根借,借此为权排序,然后贪心即可。
#define ll long long
#define fi first
#define se second
const int maxn=1e6+5;
ll ans=0;
int n,tot;
int dep[maxn];
int tmp=0;
int pre=-1;
vector<pair<int,int> >g[maxn];
//作用很简单,统计每条边所连向的子树的深度最大值,注意,此处没存到点上,存到了边上,并将边对应的子树按深度排序,好处自己领悟,懒得写了。
int dfs1(int now,int len){
    dep[now]=len;
    if(g[now].empty()){
        return 0;
    }
    for(auto &x:g[now]){
        x.fi=dfs1(x.se,len+1);
    }
    sort(g[now].begin(),g[now].end());
    return g[now].back().fi+1;
}


void dfs2(int now){
//当遍历到叶子节点时,贪心判断为链还是边数*2 
    if(g[now].empty()){
        ans+=min(tmp,dep[now]);
        tmp=0;
        return ;
    }
    for(auto x:g[now]){
        tmp++;
        dfs2(x.se);
        tmp++;
    }
}
signed main(){
    int _;scanf("%d",&_);
    while(_--){
        scanf("%d",&n);
        ans=tmp=0;
        for(int i=1;i<=n;i++){
            g[i].clear();
        }
        for(int i=2,x;i<=n;i++){
            scanf("%d",&x);
            g[x].push_back({0,i});
        }
        dfs1(1,0);
        dfs2(1);
        printf("Case #%d: %lld\n",++tot,ans);
    }
    return 0;
}


// 方法1:将边重叠的神奇贪心,思路来自于jls

// const int N = 1e6+5;
// vector<int> dep;
// int f[N];

// int main(){
//     ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//     int T;cin >> T;
//     for(int tt=1;tt<=T;tt++){
//         int n;cin >> n;
//         dep.resize(n);
//         for(int i=1;i<n;i++){
//             int u;cin >> u;
//             u--;
//             f[i] = u;
//             dep[i] = dep[u] + 1;
//         }
//         vector<int> mx(dep);
//         int ans = 0;
//         for(int i=n-1;i>=1;i--){
//             ans += max(0,min(2,2 * dep[i] - mx[i]));
//             mx[f[i]] =max(mx[f[i]],mx[i]);
//         }
//         cout << "Case #"  << tt  << ": " << ans << endl;
//     }
// }
posted @ 2022-07-16 11:05  mafengfa  阅读(44)  评论(0)    收藏  举报