1.树状DP实质:
通过转移方程使得可以由一个点的状态得到另外一个点的状态(例:树的带权重心中,由关于f[u]的转移方程能够得到f[v]的答案,附上链接)
2.关于转移方程的移动方向:
u->v,f[u]的信息被每一个v使用,链接
v->u,所有f[v]的信息被u聚合起来使用,无链接(参见普通的树的带权重心)
3.一般要先v->u收集总数据到最终根节点,再用最终根节点的总数据转移状态改变到各个子节点去
4.附上自己 树的带权重心的代码,题目
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> using namespace std; const int N = 110; const int M = 10010; struct node { int v, next; } e[M]; int p[N], eid; void init() { memset(p, -1, sizeof(p)); eid = 0; } void insert(int u, int v) { e[eid].v = v; e[eid].next = p[u]; p[u] = eid++; } int size[N], sum[N], f[N]; int n; int dfs1(int u, int fa) { int sumSon = 0; f[u] = 0; for(int i = p[u]; i != -1; i = e[i].next) { int v = e[i].v; if(v != fa) { int son = dfs1(v, u); sumSon += son; f[u] += f[v]+son; } } sumSon += size[u]; sum[u] = sumSon; return sumSon; } int dfs2(int u, int fa) { for(int i = p[u]; i != -1; i = e[i].next) { int v = e[i].v; if(v != fa) { f[v] = f[u]+sum[1]-2*sum[v]; dfs2(v, u); } } } int main() { init(); scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &size[i]); int v; scanf("%d", &v); if(v) { insert(i, v); insert(v, i); } scanf("%d", &v); if(v) { insert(i, v); insert(v, i); } } dfs1(1, -1); dfs2(1, -1); int ans = 2147483647; for(int i = 1; i <= n; i++) ans = min(ans, f[i]); printf("%d", ans); return 0; }