codeforces 743D. Chloe and pleasant prizes

来源:互联网 发布:建筑虚拟仿真软件 编辑:程序博客网 时间:2024/04/28 06:07

题目大意:给定一个以1为根结点的树,树上每个节点都有一个权值。求取两个不相交的子树。使两个子树的权值和最大。刚看到这个题目的时候,以为只需要求出每个子树的最大权值,然后先选取一个最大的,然后把相关的子树和该点到父节点的的路径上的所有点去掉,再去找一最大,就可以了。提交,果断WA。然后看数据,找错误,然后还是各种WA。最后仔细思考,这种方法其实是不对的,举个例子,假设对于某个子树A,当前权值和最大时,那么,如果选了它,我们在去找一个符合条件的子树B,如果B的权值和为负数,那么sum(A)+sum(B) < sum(A),那么就可能会存在:选A的两个子树C,D。虽然sum(C) + sum(D) < sum(A) 但是可能会有sum(C) + sum(D) > sum(A) + sum(B)。所以,这种方法行不通。最初的想法不对,重新思考。树型结构就是一个天然的递规结构(每个节点的子树又可以看成一棵树),往DP上思考。题目是求两个没有交集的子树的权值最大和,那么能不能,直接去求以每个节点为根节点时能得到的最大的两个不相交的子树的和。这样,就可以将大问题分解为小问题,那接下来就是考虑如何合并的问题。那么仔细想想,合并并不难。合并时:对于以每个节点为树根的树,由于其每个子树的结果已经有了,那么,需要考虑两种情况,一个是答案就在某个子树中,另一个是,答案是由两个子树(最大权值和分别为第一和第二)的最大权值和相加的结果。那么这样,就还需要维护以每个节点为根的子树的最大权值和,记为T。不难发现,要维护每个节点的T,还需要维护以每个节点为根的子树的权值和。最后,求出问题的解。当然,当这个树为只有一个叶子节点时,就是无解的情况!具体看代码,由于最近在学习GO语言,所以,代码用GO语言写的。不过也比较好懂!

package mainimport ("bytes""fmt""io/ioutil""os")const MAX = 200010const INF = int64(200000000000000)type Edge struct {x, y int}type Node struct {ans, maxn, sum int64}var a []int64var d []Nodevar vis []boolvar c []intvar first []intvar next []intvar edges []Edgevar cnt intfunc addEdge(u, v int) {cnt++edges[cnt].x = uedges[cnt].y = vnext[cnt] = first[u]first[u] = cnt}func max(x, y int64) int64 {if x > y {return x}return y}func dp(root int) Node {if vis[root] {return d[root]}d[root].ans = -INFd[root].maxn = -INFd[root].sum = a[root]vis[root] = truex := -INFy := -INFfor i := first[root]; i != 0; i = next[i] {u := edges[i].yif !vis[u] {tmp := dp(u)d[root].maxn = max(d[root].maxn, tmp.maxn)d[root].sum += tmp.sumd[root].ans = max(d[root].ans, tmp.ans)if tmp.maxn > x {y = xx = tmp.maxn} else if tmp.maxn > y {y = tmp.maxn}}}d[root].maxn = max(d[root].maxn, d[root].sum)if x > -INF && y > -INF {d[root].ans = max(d[root].ans, x+y)}return d[root]}func main() {var n intb, _ := ioutil.ReadAll(os.Stdin)r := bytes.NewReader(b)fmt.Fscanf(r, "%d\n", &n)a = make([]int64, n+1)d = make([]Node, n+1)vis = make([]bool, n+1)c = make([]int, n+1)first = make([]int, n+1)next = make([]int, 2*n+1)edges = make([]Edge, 2*n+1)cnt = 0for i := 1; i < n; i++ {fmt.Fscanf(r, "%v ", &a[i])}fmt.Fscanf(r, "%v\n", &a[n])var u, v intfor i := 1; i < n; i++ {fmt.Fscanf(r, "%d %d\n", &u, &v)c[u]++c[v]++addEdge(u, v)addEdge(v, u)}dp(1)ans := d[1].ansif ans <= -INF {fmt.Printf("Impossible\n")} else {fmt.Printf("%v\n", ans)}return}


0 0