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\n");
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

猜你喜欢

转载自www.cnblogs.com/snowy2002/p/10276297.html