由 树的带权重心 衍申的对 树状DP 的感悟

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;
}

 

posted @ 2021-01-24 21:32  bear_xin  阅读(75)  评论(0)    收藏  举报