zoukankan      html  css  js  c++  java
  • CF767C Garland--树形dp

    今天无聊的我又来切树形dp了,貌似我与树形dp有仇似的。

    n个节点的树

    i个节点权值为 n<=10^6

     −100<=ai<=100

    问是否能够删除掉两条边,使得该树分成三个不为空,并且每部分权值之和相等.

    无解输出1 否则输出要删除边(u>v)的v节点序号.

    说白了就是把一棵树分成三块连通图,并且每个连通图权值相同,那么我们不管怎么切都会切出以某个结点为根的子树。由于每个点的权值都是整数,那么我们先用总权值 mod 3看看能不能整除,如果不能就输出-1,如果可以那么每个子树肯定权值都是 w/3 (w为总权值)。接着就跑树形dp咯,设f[x]代表以x为根的子树的权值和(包括x在内),如果某一个f[x]== w/3 我们就统计一下,如果一个树上有三个这样的根节点,那么就把这三个根节点和他们的父亲的边切了,这样就得到了我们想要的结果了,所以统计一下这样的点的数量就行,最后判断一下是否三个这样的点。

    接下来就是愉快的代码时间:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cmath>
     5 #include<cstring>
     6 #include<queue>
     7 #include<stack>
     8 #include<algorithm>
     9 #define maxn 1000005
    10 using namespace std;
    11 
    12 struct edge
    13 {
    14     int next;
    15     int to;
    16 }g[maxn<<1];
    17 
    18 inline int read()
    19 {
    20     char c=getchar();
    21     int res=0,x=1;
    22     while(c<'0'||c>'9')
    23     {
    24         if(c=='-')
    25         x=-1;
    26         c=getchar();
    27     }
    28     while(c>='0'&&c<='9')
    29     {
    30         res=res*10+(c-'0');
    31         c=getchar();
    32     }
    33     return x*res;
    34 }
    35 
    36 int n,num,aa,bb,root,sum,cnt,ans[10];
    37 int last[maxn],f[maxn],d[maxn];
    38 
    39 inline void add(int from,int to)
    40 {
    41     g[++num].next=last[from];
    42     g[num].to=to;
    43     last[from]=num;
    44 }
    45 
    46 void dfs(int x)
    47 {
    48     d[x]=1;
    49     for(int i=last[x];i;i=g[i].next)
    50     {
    51         int v=g[i].to;
    52         if(!d[v])
    53         {
    54             dfs(v);
    55             f[x]+=f[v];
    56         }
    57     }
    58     if(f[x]==sum)
    59     {
    60         ans[++cnt]=x;
    61         f[x]=0;
    62     }
    63 }
    64 
    65 int main()
    66 {
    67     n=read();
    68     for(int i=1;i<=n;i++)
    69     {
    70         aa=read();bb=read();
    71         f[i]=bb;
    72         sum+=bb;
    73         if(aa==0)
    74         {
    75             root=i;
    76         }
    77         else
    78         {
    79             add(i,aa);
    80             add(aa,i);
    81         }
    82     }
    83     if(sum%3!=0)
    84     {
    85         printf("-1
    ");
    86         return 0;
    87     }
    88     else 
    89     {
    90         sum=sum/3;
    91         dfs(root);
    92         if(cnt<=2)
    93         printf("-1");
    94         else 
    95         printf("%d %d",ans[1],ans[2]);
    96         return 0;
    97     }
    98 }
    View Code

    If you fail, don't forget to learn your lesson.
    如果你失败了,千万别忘了汲取教训。

                                                                                                      --snowy

                                                                                          2019-01-16    12:02:52

  • 相关阅读:
    nginx socket转发设置
    Linux CentOS 7 安装字体库 & 中文字体
    nginx配置location总结及rewrite规则写法
    nginx动静分离小示例
    iptables黑/白名单设置(使用ipset 工具)
    Docker logs 命令
    Docker定制容器镜像(利用Dockerfile文件)
    docker swarn集群笔记
    [国家集训队]数颜色 / 维护队列(带修莫队)
    于是他错误的点名开始了(trie树)
  • 原文地址:https://www.cnblogs.com/snowy2002/p/10276297.html
Copyright © 2011-2022 走看看