zoukankan      html  css  js  c++  java
  • [51NOD1405] 树的距离之和(树DP)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1405

    (1)我们给树规定一个根。假设所有节点编号是0-(n-1),我们可以简单地把0当作根,这样下来父子关系就确定了。

    (2)定义数组num[x]表示以节点x为根的子树有多少个节点,dp[x]是我们所求的——所有节点到节点x的距离之和。
    (3)在步骤(1)中,其实我们同时可以计算出 num[x],还可以计算出每个节点的深度(每个到根节点0的距离),累加全部节点深度得到的其实就是是dp[0]。
    (4) 假设一个非根节点x,它的父亲节点是y, 并且dp[y]已经计算好了,我们如何计算dp[x]?  
    以x为根的子树中那些节点,到x的距离比到y的距离少1, 这样的节点有num[x]个。
    其余节点到x的距离比到y的距离多1,这样的节点有(n - num[x])个。
    于是我们有 dp[x] = dp[y] - num[x] + (n - num[x]) = dp[y] + n - num[x] * 2
    因为树的根节点dp[0]在步骤(3)已经计算出来了,根据所有的父子关系和这个上式,我们可以按照顺序计算出整个dp数组。特别像多校的一道题,或者说这类题都很类似。
     1 #include <bits/stdc++.h>
     2 #include<ext/pb_ds/assoc_container.hpp>
     3 #pragma comment(linker, "/STACK:10240000,10240000")
     4 using namespace std;
     5 using namespace __gnu_pbds;
     6 
     7 typedef long long LL;
     8 const int maxn = 200100;
     9 vector<int> G[maxn];
    10 LL num[maxn];
    11 LL dp[maxn];
    12 int n;
    13 
    14 LL dfs1(int u, int p, LL d) {
    15   int cnt = 1;
    16   num[u] = cnt;
    17   dp[1] += d;
    18   for(int i = 0; i < G[u].size(); i++) {
    19     int v = G[u][i];
    20     if(v == p) continue;
    21     num[u] += dfs1(v, u, d+1);
    22   }
    23   return num[u];
    24 }
    25 
    26 void dfs2(int u, int p) {
    27   for(int i = 0; i < G[u].size(); i++) {
    28     int v = G[u][i];
    29     if(v == p) continue;
    30     dp[v] = dp[u] + n - num[v] * 2;
    31     dfs2(v, u);
    32   }
    33 }
    34 
    35 int main() {
    36   //freopen("in", "r", stdin);
    37   int u, v;
    38   while(~scanf("%d", &n)) {
    39     memset(num, 0, sizeof(num));
    40     memset(dp, 0, sizeof(dp));
    41     for(int i = 1; i <= n; i++) G[i].clear();
    42     for(int i = 1; i < n; i++) {
    43       scanf("%d%d",&u,&v);
    44       G[u].push_back(v);
    45       G[v].push_back(u);
    46     }
    47     dfs1(1, -1, 0);
    48     dfs2(1, -1);
    49     for(int i = 1; i <= n; i++) printf("%lld
    ", dp[i]);
    50   }
    51   return 0;
    52 }
  • 相关阅读:
    [AHOI2006]文本编辑器 Splay tree区间操作
    HDU-3487 Play with Chain Splay tee区间反转,移动
    HDU-4619 Warm up 2 二分匹配
    HDU-4618 Palindrome Sub-Array 暴力枚举
    HDU-4616 Game 树形DP
    HDU-4614 Vases and Flowers 线段树区间更新
    HDU-4612 Warm up 边双连通分量+缩点+最长链
    HDU-4611 Balls Rearrangement 循环节,模拟
    HDU-4605 Magic Ball Game 树状数组+离散+dfs
    HDU-3436 Queue-jumpers 树状数组 | Splay tree删除,移动
  • 原文地址:https://www.cnblogs.com/kirai/p/5994870.html
Copyright © 2011-2022 走看看