zoukankan      html  css  js  c++  java
  • 联考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\n",mx[1]);
    }
    

  • 相关阅读:
    Hznu_0j 1533 计算球体积(水)
    电子警察
    UVA ——利用常量数组
    排序算法
    分解质因数
    几种数
    动态规划
    C. The Football Season (枚举) ( Codeforces Round #592 (Div. 2) )
    Fibonacci前n项和 (矩阵乘)
    2153: D.ly的排队问题 (拓扑排序)(vector , set , priority_queue )
  • 原文地址:https://www.cnblogs.com/IzayoiDoyo/p/13377310.html
Copyright © 2011-2022 走看看