VIrtuoso

两把多兰剑加个布甲鞋

导航

Codeforces Round #514 (Div. 2) E. Split the Tree(倍增+贪心)

https://codeforces.com/contest/1059/problem/E

题意

给出一棵树,每个点都有一个权值,要求你找出最少条链,保证每个点都属于一条链,而且每条链不超过L个点 和 每条链的权值和不超过S

题解

  • 对于儿子来说,父亲节点只有一个,所以没有决策点。可以从下往上处理出,每个节点最远能爬到那个节点(过程就是倍增)
  • 然后从下往上贪 (选择往上走的远的子节点)
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define N 100005
using namespace std;
vector<int>g[N];
int n,l,i,v,u,ans,f[N][25],d[N],top[N],pre[N];
ll s,w[N],sum[N];

void dfs(int u,int fa){
    sum[u]=sum[fa]+w[u];
    d[u]=d[fa]+1;
    f[u][0]=fa;
    for(i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
    top[u]=u;
    
    int D=l;
    for(i=20;i>=0;i--){
        int v=f[top[u]][i];
        if(v==0||(1<<i)>=D||sum[u]-sum[f[v][0]]>s)continue;
        D-=(1<<i);
        top[u]=v;
    }
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];dfs(v,u);
    }
}

void dfs2(int u){
   int bt=0;
   for(int i=0;i<g[u].size();i++){
      int v=g[u][i];
      dfs2(v);
      if(pre[v]==v)continue;
      if(!bt||d[bt]>d[pre[v]])bt=pre[v];
   }
   if(!bt){ans++;bt=top[u];}
   pre[u]=bt;
}
int main(){
   cin>>n>>l>>s;
   for(i=1;i<=n;i++){
       scanf("%lld",&w[i]);
       if(w[i]>s){cout<<-1;return 0;}
   }
   for(i=2;i<=n;i++){
       scanf("%d",&v);
       g[v].pb(i);
   }
   ans=0;
   dfs(1,0);
   dfs2(1);
   cout<<ans<<endl;
}

posted on 2018-11-16 19:57  VIrtuoso  阅读(116)  评论(0编辑  收藏  举报