2020CCPC秦皇島 k Kingdom’s Power


2020CCPC秦皇島 k Kingdom’s Power

題意是說給定一顆以1為根的樹,根節點處有無數個人,每一秒只能派一個人移動到他的相鄰節點上,問最少需要多少秒才能使所有結點被訪問過。

  • 類似一個樹形dp。
  • 把每個結點的val,初始化為從根走到它的步數。
  • 一個初步的想法是,要盡可能把走到葉子結點的人也利用起來,避免從根節點走浪費太多秒。
  • 設想一種情況,當前深度為10的結點A存在2條子鏈,左邊的長度為3,右邊的長度為5,那么最優的走法是從當前結點走向左邊,再由左邊的葉子走向右邊的葉子。
  • 注意從左葉子回溯到A的時候,對應的步數不能直接更新為A的val,因為它只能被利用一次。因此對於一個結點,我們要按子樹高度大小升序遍歷。
  • 對於某個結點,按照以上策略,往回回溯給出的值與它的最深的葉子有關,所以子樹的高度應為它最高的子樹h+1。

空間復雜度O(N)
時間復雜度O(nlogn)
跟CJH大佬一起口胡搞出來的思路

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int val[maxn];
int fa[maxn];
vector<pair<int,int> > son[maxn];//height,NO
void init(int n){
    for(int i=1;i<=n;++i)
        son[i].clear();
}
int geth(int rt){
    if(son[rt].empty()) return 1;
    for(int i=0;i<son[rt].size();++i){
        son[rt][i].first=geth(son[rt][i].second);
    }
    sort(son[rt].begin(),son[rt].end());
    return son[rt].back().first+1;
}
int dfs2(int rt,int d,int v){
    val[rt]=v;
    if(son[rt].empty()) return 1;
    int t=v;
    for(int i=0;i<son[rt].size();++i){
        t=min(d,dfs2(son[rt][i].second,d+1,t+1));
    }
    return t+1;
}

int main(){
    // freopen("in.txt","r",stdin);
    // ios::sync_with_stdio(false);
    int t,n;
    scanf("%d",&t);
    for(int ca=1;ca<=t;++ca){
        scanf("%d",&n);
        init(n);
        for(int i=2;i<=n;++i){
            scanf("%d",fa+i);
            son[fa[i]].push_back({0,i});
        }
        geth(1);
        dfs2(1,0,0);
        ll ans=0;
        for(int i=1;i<=n;++i)
            if(son[i].empty())
                ans+=val[i];
        printf("Case #%d: %lld\n",ca,ans);
    }
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM