zoukankan      html  css  js  c++  java
  • CF1059E Split the Tree

    LXIV.CF1059E Split the Tree

    我们假设对于每个位置,已经求出了它可以往上延伸的长度\(len[x]\),然后考虑DP。

    \(g[x]\)表示子树被分完后的最小边的数量。再设\(f[x]\)表示当这个数量最小时,点\(x\)能够往上延伸的最长长度。

    这运用了贪心的思想:因为\(g[x]\)少一条边,肯定是要比\(f[x]\)无论大多少都是要更优的\(f[x]\)再大,也只对一条边有效,\(f\)中一条边和\(g\)中一条边,不都是一样的吗?

    我们可以很轻松地得到转移方程:

    \(f[x]=\max\limits_{y\in Sons_x}\{f[y]\}-1,g[x]=\sum\limits_{y\in Sons_x}g[y]\)

    如果在上面的转移方程中,得到了\(f[x]=-1\),那就意味着必须在\(x\)位置开新边,令\(f[x]=len[x]\)\(g[x]\)加一。

    现在主要的部分就是求出\(len[x]\)了。这个可以通过倍增法在\(O(n\log n)\)时间里预处理出来。

    则总复杂度为\(O(n\log n)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int n,L,S,val[100100],len[100100],anc[100100][20],sum[100100],dep[100100],f[100100],g[100100];
    vector<int>v[100100];
    void dfs1(int x){
    	for(int i=1;(1<<i)<=dep[x];i++)anc[x][i]=anc[anc[x][i-1]][i-1];
    	for(int i=19,y=x;i>=0;i--){
    		if(!anc[y][i])continue;
    		if(sum[x]-sum[anc[y][i]]+val[anc[y][i]]>S)continue;
    		if(dep[x]-dep[anc[y][i]]>=L)continue;
    		len[x]+=(1<<i),y=anc[y][i];
    	}
    	for(auto y:v[x])anc[y][0]=x,dep[y]=dep[x]+1,sum[y]=sum[x]+val[y],dfs1(y);
    }
    void dfs2(int x){
    	for(auto y:v[x])dfs2(y),f[x]=max(f[x],f[y]),g[x]+=g[y];
    	f[x]--;
    	if(f[x]==-1)f[x]=len[x],g[x]++;
    }
    signed main(){
    	scanf("%lld%lld%lld",&n,&L,&S);
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&val[i]);
    		if(val[i]>S){puts("-1");return 0;}
    	}
    	for(int i=2,x;i<=n;i++)scanf("%lld",&x),v[x].push_back(i);
    	dep[1]=1,sum[1]=val[1],dfs1(1),dfs2(1);
    //	for(int i=1;i<=n;i++)printf("%lld ",len[i]);puts("");
    	printf("%lld\n",g[1]);
    	return 0;
    } 
    

  • 相关阅读:
    迭代器与生成器
    函数
    Java多线程
    JVM垃圾回收
    JVM内存模型
    面向对象的特征和原则
    Java代码规范
    安装yum
    虚机ping:www.baidu.com报错
    创建好centos7虚拟机之后连xshell连不上虚机
  • 原文地址:https://www.cnblogs.com/Troverld/p/14597543.html
Copyright © 2011-2022 走看看