P1364 医院设置 【带权值的树的重心】

题目

https://www.luogu.com.cn/problem/P1364

 

 思路

该题是典型的找树的重心的题型,但是特殊的是它是一个带权树的重心。

 

 它是首先初始化一个f,即一个点到其它点的距离,这里为了方便就直接初始化了1号节点,之后在dp函数中来计算其他节点的f值

当根从u变为v的时候,v的子树的所有节点原本的距离要到u,现在只要到v了,每个结点的距离都减少1,那么总距离就减少size[v],

同时,以v为根的子树以外的所有节点,原本只要到u就行了,现在要到v,每个节点的路程都增加了1

总路程就增加size[1]size[v],其中size[1]就是我们预处理出来的整棵树的大小,减去size[v]就是除以v为根的子树以外的结点数。

 代码

#include<iostream>
#include<cstdio>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 200
#define maxm 5000
struct edge
{
    int to;
    int next;
}e[maxm*2];
int head[maxn], vis[maxn],amount[maxn], num[maxn],f[maxn],cnt = 0;
int n, minn = 999999;
void addedge(int u,int v)
{
    cnt++;
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}

void dfs(int p, int fa,int depth)
{
    num[p] = amount[p];
    for (int i = head[p]; i; i = e[i].next)
    {
        int y = e[i].to;
        if (y == fa)continue;
        dfs(y, p,depth+1);
        num[p] += num[y];
    }
    f[1] += amount[p] * depth;
}

void dp(int p, int fa)
{
    for (int i = head[p]; i; i = e[i].next)
    {
        int y = e[i].to;
        if (y == fa)continue;
        f[y] = f[p] + num[1] - num[y] * 2;
        dp(y, p);
    }
    minn = min(minn, f[p]);

}


int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        int w, u, v;
        scanf("%d%d%d", &w, &u, &v);
        amount[i] = w;
        if (u != 0)
        {
            addedge(i, u);
            addedge(u, i);
        }
        if (v != 0)
        {
            addedge(i, v);
            addedge(v, i);
        }
    }
    dfs(1, 0,0);
    dp(1, 0);
    printf("%d", minn);

}

 

posted @ 2020-06-28 09:10  Jason66661010  阅读(447)  评论(0编辑  收藏  举报