• CF767C Garland 【树形dp】By cellur925


    一句话题意:给定一个树,树有点权,要求把树的某些边删去,使树变成三个部分,每部分点权值和相等。

    我们很容易想到,再读入的时候记录所有点的点权之和,点权除以3是最后权值相等的值。如果不能整除3一定无解,可以结束程序。

    那么之后?

    我们很自然地想到,状态可以设计为:f[i]为以i为根的子树上的点权和。边界为它自身点权(初值)。

    转移也就很自然,f[i]=sigma f[j],j枚举i的儿子。但是很有可能儿子上的权值就满足最后的权值,我们就可以干掉这颗子树,继续遍历当前主树。最后两个断点就先从小子树中找到,再从较大子树中找到。

    值得我们注意的是,这的确是一棵有根树,提链的老哥手里攥着的灯泡就是根,根是不能作为断点的。这点需要特别注意。

    code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<vector>
     4 
     5 using namespace std;
     6 
     7 int n,sum,root;
     8 int x=-2,y=-2;
     9 int f[1000090];
    10 int val[1000090];
    11 vector<int>son[1000090];
    12 
    13 void TreeDp(int u,int fa)
    14 {
    15     f[u]=val[u];
    16     for(int i=0;i<son[u].size();i++)
    17     {
    18         int v=son[u][i];
    19         if(v==fa) continue;
    20         TreeDp(v,u);
    21         if(f[v]==sum&&y==-2) y=v; 
    22         else f[u]+=f[v];
    23     }
    24     if(f[u]==sum&&x!=root&&y!=-2) x=u;
    25 }
    26 
    27 int main()
    28 {
    29     scanf("%d",&n);
    30     for(int i=1;i<=n;i++)
    31     {
    32         int u=0,w=0;
    33         scanf("%d%d",&u,&w);
    34         sum+=w;
    35         if(u==0) root=i;
    36         val[i]=w;
    37         son[u].push_back(i);
    38     }
    39 //    printf("%d
    ",sum);
    40     if(sum%3!=0)
    41     {
    42         printf("-1");
    43         return 0;
    44     }
    45     sum/=3;
    46     TreeDp(root,-2);
    47     if(x!=-2&&x!=root) printf("%d %d",x,y);
    48     else printf("-1");
    49     return 0;
    50 }
    View Code
  • 相关阅读:
    Git回退---reset和revert
    XML解析
    SpringBoot学习day01
    Spring boot精要
    JS没有contains方法,可以用indexof实现
    git fetch 取回所有分支(branch)的更新(转)
    idea 设置注释模板
    git退出编辑模式
    git 提交代码到远程分支
    linux下,保存退出vim编辑器(转)
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9457341.html
Copyright © 2020-2023  润新知