• 联考20200725 T2 Tree





    分析:
    神仙DP,又被开除人籍了
    整个过程是LCT逆过程?(雾)
    设状态(f_{i,j})表示以(i)号点为根,构成一棵大小为(j)的二叉树变换为一条链的整棵子树的最大深度
    画个图便于理解:

    考虑如何转移,一个点(i)作为根的二叉树在中序遍历情况下,它的左子树全部节点会成为(i)的祖先,对(i)和子树内剩下节点的深度造成影响
    右子树会成为(i)的后代,不会影响其余点的深度,但是其大小会统计到(i),以便再向上DP
    然后剩下的儿子会接在(i)上,向上统计时全部节点深度加一再加上去就可以了
    我们把儿子排成一行,一个一个合并时,在里面选两个作为左右儿子,我们假设左儿子在右儿子前面选

    右儿子在左儿子前边的情况倒序做就行了
    根节点为(u),考虑目前统计到儿子(v),想让(v)做右儿子,大小为(j)
    那么要在(v)前面选出一个左儿子大小为(i),且与其他非关键儿子向上合并得到的深度和最大
    再开一个数组(g_{u,i})表示,目前(u)已经统计过的儿子里,某一个大小为(i)的子树作为左儿子,与其他非关键儿子向上合并得到的深度和的最大值
    这两个dp值可以同时维护
    还要注意一下一个点没有右儿子的情况,处理左儿子时直接统计答案
    好像有点口胡,还是看代码吧(
    复杂度(O(n^2))

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<vector>
    #include<string>
    
    #define maxn 5005
    #define INF 0x3f3f3f3f
    #define MOD 998244353
    #define eps 1e-10
    
    using namespace std;
    
    inline long long getint()
    {
    	long long num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n;
    vector<int>G[maxn];
    int f[maxn][maxn],g[maxn][maxn],mx[maxn],sz[maxn];
    
    inline void dfs(int u)
    {
    	int Sz=0,Sum=0;
    	for(int i=0;i<G[u].size();i++)
    		dfs(G[u][i]),Sz+=sz[G[u][i]],Sum+=mx[G[u][i]];
    	f[u][1]=g[u][0]=Sum;
    	for(int i=0;i<G[u].size();i++)
    	{
    		int v=G[u][i];
    		for(int i=0;i<=sz[u];i++)for(int j=1;j<=sz[v];j++)
    			f[u][i+j+1]=max(f[u][i+j+1],g[u][i]+f[v][j]-mx[v]+sz[v]+i);
    		sz[u]+=sz[v];
    		for(int i=1;i<=sz[v];i++)
    			g[u][i]=max(g[u][i],Sum+f[v][i]-mx[v]+i*(Sz-sz[v])),
    			f[u][i+1]=max(f[u][i+1],Sum+f[v][i]-mx[v]+i*(Sz-sz[v]));
    	}
    	memset(g[u],-INF,sizeof g[u]);
    	g[u][0]=Sum,sz[u]=0;
    	for(int i=G[u].size()-1;~i;i--)
    	{
    		int v=G[u][i];
    		for(int i=0;i<=sz[u];i++)for(int j=1;j<=sz[v];j++)
    			f[u][i+j+1]=max(f[u][i+j+1],g[u][i]+f[v][j]-mx[v]+sz[v]+i);
    		sz[u]+=sz[v];
    		for(int i=1;i<=sz[v];i++)
    			g[u][i]=max(g[u][i],Sum+f[v][i]-mx[v]+i*(Sz-sz[v])),
    			f[u][i+1]=max(f[u][i+1],Sum+f[v][i]-mx[v]+i*(Sz-sz[v]));
    	}
    	sz[u]++;
    	for(int i=1;i<=sz[u];i++)mx[u]=max(mx[u],f[u][i]);
    	mx[u]+=sz[u];
    }
    
    int main()
    {
    	n=getint();
    	for(int i=2;i<=n;i++)G[getint()].push_back(i);
    	memset(f,-INF,sizeof f),memset(g,-INF,sizeof g);
    	dfs(1);
    	printf("%d
    ",mx[1]);
    }
    

  • 相关阅读:
    PHP文件系统处理(二)
    PHP中的文件系统处理(一)
    PHP中常用正则表达式大全
    PHP中的正则表达式的使用
    SLF4J日志框架
    内部类
    计算机存储单位
    Maven 要点
    Maven 父类工程创建及引用
    Eclipse Maven Web项目创建
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13377310.html
Copyright © 2020-2023  润新知