zoukankan      html  css  js  c++  java
  • 题目分享Q

    题意:给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大

    分析:这可以说是换根法的裸题吧

    首先考虑对一个给定的根如何计算,这应该是最简单的那种树形dp吧甚至可能都不算dp(好像还真不算dp)

    dp[i]表示i点所有孩子(包括自己)的深度之和

    deep[i]表示i点的深度

    dp[x]=sum(dp[v]) +deep[x]    v|v是x的子节点

    用一遍dfs即可搞定dp[1]-dp[n]

    当然这里用谁为根都可以,用1就行

     比如我们现在已经处理出dp[1]-dp[n]的值

    因为如果我们用2做根的时候,虽然发现所有人的dp值都改变了(每个人深度都改变了),这与我们之前学习的换根法可能会有一点区别

     但能发现的是,我们当前根节点的儿子想上位所需要改变的东西(dp值)其实O(1)就可以解决,或者说有规律可言,所以我们可以用换根法

    那么怎么改变?或者说有什么规律?

    首先要先记住一点的还是那个状态转移方程      dp[x]=sum(dp[v]) +deep[x]    v|v是x的子节点

    再考虑这里面中每一项都怎么变的

    就拿原来根是1换成2来说

    首先,1除了2以外的子树的所有节点包括1在内(1,3,6,7,8),深度都+1

    而2的子树包括2在内(2,3,5),深度都-1

    然后好像就没啥别的变化了

    那么再看dp值是怎么变的

    首先dp[1]的值要先减去dp[2]的值,得到1除了2以外的子树包括1在内的深度之和,而得到这个之和dp[1]还要加上这些节点的个数,因为每个节点的深度都加一嘛

    用son[i]表示i的子节点个数(包括自己)

    也就是说dp[1]=dp[1]-dp[2]+(son[1]-son[2])(这是1除了子树2以外的节点数目)

    而dp[2]是要先减去节点个数,再加上当前1的dp值(dp[1]修改后的值),因为此时1已经是2的儿子了

    dp[2]=dp[2]-son[2]+dp[1]

    注意这里是有先后顺序的

    当然我们在第一遍dfs的时候要多算一遍son[i]

    还有一点细节

    在我们换根的时候要记得dfs完这个子树要还原成原来的样子再dfs下一个子树,而我们在dfs子树的时候其实与根节点是没有关系的,dfs只能往下搜嘛

    也就是说我们在交换1和2的时候dp[1]的值不需要修改,所以我直接把dp[1]的式子带入到dp[2]的式子里就行了,也就是

    dp[2]=dp[2]-son[2]+dp[1]-dp[2]+son[1]=dp[1]+son[1]-son[2]*2

    最后把以所有点为根的结果取个最值就行了

    代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<vector>
     4 using namespace std;
     5 
     6 #define ll long long
     7 
     8 const int maxn=1e6+1;
     9 
    10 struct Node
    11 {
    12     int to,next;
    13 }e[maxn<<1];
    14 int head[maxn];
    15 ll dp[maxn];
    16 int son[maxn];
    17 int cnt,k,n;
    18 ll maxans;
    19 
    20 void add(int x,int y)
    21 {
    22     e[++cnt].to=y;
    23     e[cnt].next=head[x];
    24     head[x]=cnt;
    25 }
    26 
    27 void dfs1(int x,int fa,int now)
    28 {
    29     dp[x]=(ll)now,son[x]=1;
    30     for(int i=head[x];i;i=e[i].next)
    31     {
    32         int v=e[i].to;
    33         if(v!=fa)
    34         {
    35             dfs1(v,x,now+1);
    36             dp[x]+=dp[v];
    37             son[x]+=son[v];
    38         }
    39     }
    40 }
    41 
    42 void dfs2(int x,int fa)
    43 {
    44     if(dp[x]>maxans||dp[x]==maxans&&x<k) k=x,maxans=dp[x];
    45     for(int i=head[x];i;i=e[i].next)
    46     {
    47         int v=e[i].to;
    48         if(v!=fa)
    49         {
    50             ll now=dp[x]-dp[v]+(ll)son[x]-(ll)son[v]*2;//这里是为了方便还原,下面用的+=和-=
    51             int nowv=son[v];
    52             son[v]=son[x];
    53             dp[v]+=now;
    54             dfs2(v,x);
    55             dp[v]-=now;
    56             son[v]=nowv;
    57         }
    58     }
    59 }
    60 
    61 int main()
    62 {
    63     int n,x,y;
    64     scanf("%d",&n);
    65     for(int i=1;i<n;i++)
    66     {
    67         scanf("%d%d",&x,&y);
    68         add(x,y);add(y,x);
    69     }
    70     dfs1(1,-1,1);dfs2(1,-1);
    71     printf("%d",k);
    72     return 0;
    73 }
  • 相关阅读:
    [译文] 实体与值对象到底是不是一回事?
    实现 WebApi 自托管服务宿主于 WinForms 及其交互
    [译文] C# 8 已成旧闻, 向前, 抵达 C# 9!
    [译文] 为什么你在 C# 里总是应该使用 "var" 关键字
    通过设置iis在局域网中访问网页
    windows 10 安装使用kafka
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 4) 整合Polly实现瞬时故障处理
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 3) 使用Handler实现传出请求中间件
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 2) 定义命名化和类型化的客户端
    Asp.net Core 2.0 OpenId Connect Handler缺失Claims?
  • 原文地址:https://www.cnblogs.com/lin4xu/p/12691031.html
Copyright © 2011-2022 走看看