树上DFS + DP,一般用 \(f_{i,\cdots}\) 表示以 \(i\) 为根的子树的状态。
树上dp¶
树上背包¶
课程里有些课程必须在某些课程之前学习,现在有 \(N\) 门功课,每门课有个学分,每门课有一门或没有直接先修课(树),从这些课程里选择 \(M\) 门课程学习,问他能获得的最大学分是多少?
先不考虑依赖,令 \(dp[u][j]\) 表示以 \(u\) 为根,包括 \(u\) 在内选 \(j\) 门课能得到的最大学分。那么DFS到叶子时 \(j=1\) 一定要选 \(u\),\(dp[u][1]=score[u]\)。
依赖关系在转移时处理:
设处理 u 为根的树总共选修 j 门课程,则儿子们共修 j-1 门课程
若处理到儿子 v,枚举 v 儿子选修 k 门课程(0 ~ j-1)
则 u 已处理的儿子只能选择 j-1-k 门课程
换根dp¶
第一次dfs钦定一个根找答案(同时保存一些子树的数据,比如子树大小、子树权值和、子树dp答案,有时还要维护不严格次大值),第二次dfs按照dfs顺序依次翻转每一个儿子当根。
步骤¶
- 第一次dfs,算出以1为根的ans,维护子树信息(siz、dep等)。
- 第二次dfs,对于每个节点 \(u\),依次枚举其儿子 \(v\) 当作新的树根:
- 复制原来所有数组中只涉及到 u/v 的数据
- 用这些数据推算出以 \(v\) 为根的新数据,并覆盖数组中的数据
- 这一步往往是最繁琐的,可能需要很多步骤,有时不是 \(O(1)\)!
- 此时,我们就完成了 “换根” ——保证每个儿子 \(v\) 被换成根时,所有(要用到的)数据都是以 \(v\) 为根所得的数据。继续dfs即可。
- 从儿子返回,用1中复制的数据还原数组中的数据。
习题¶
注意不是 \(O(n)\),要比值排序¶
签到题
给定一颗点带权无根树,请你选定一个根并对这棵树进行深度优先遍历,得到一个点的经过顺序(即dfs序):\(v_1,v_2\cdots v_n\),记点 \(u\) 的点权为 \(A_u\),请最小化下面式子的值:\(\sum^{n}_{i=1} i\times A_{v_i}\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
|
维护次大值:¶
待完成¶
线是红色或蓝色的,珠子被编号为 \(1\) 到 \(n\)。这个游戏从一个珠子开始,每次会用如下方式添加一个新的珠子:
Append(w, v)
:一个新的珠子 \(w\) 和一个已经添加的珠子 \(v\) 用红线连接起来。Insert(w, u, v)
:一个新的珠子 \(w\) 插入到用红线连起来的两个珠子 \(u, v\) 之间。具体过程是删去 \(u, v\) 之间红线,分别用蓝线连接 \(u, w\) 和 \(w, v\)。
每条线都有一个长度。游戏结束后,你的最终得分为蓝线长度之和。
给你连珠线游戏结束后的游戏局面,只告诉了你珠子和链的连接方式以及每条线的长度,没有告诉你每条线分别是什么颜色。
你需要写一个程序来找出最大可能得分。即,在所有以给出的最终局面结束的连珠线游戏中找出那个得分最大的,然后输出最大可能得分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
|