• ZOJ 3949 Edge to the Root


    题意

      给出一颗有n个节点的树,我们想增加一条边在1到x之间,使得d(1,v)的和最小,d(u,v)代表从u到v经过的最少的边,n<=2*10^5。

    分析

      这个一看应该就是树形dp。

      如果不连这一条边,这个树本身的d(1,v)的和是多少?显然是每个点的深度的和(根结点深度为0)。那么连一条边(1,v)后,哪些点的深度受到了影响呢?首先它和它所有的子孙结点深度一定让减小。另外我们观察发现,从根结点到v路径上的中间结点以下的点节点深度也会减小。发现了这个规律应该就很好写了,实现的方法也非常多。

      我们定义f[i]是连边(1,i)的d(1,v)的和。那么怎么转移呢?

      当前在结点u,如果fa[u]的f值已经知道,如何求u的f值?我们来看,从(1,fa[u])变为(1,u),哪些点的d(1,v)发生了变化?根据上面的规律很容易找到,u结点本身及其所有的子孙结点的d(1,v)值都减少了1,而1到u路径上的中间结点以下到fa[u]这些结点的d(1,v)值是加了1的。根据这个规律很容易推出所有结点的d值。

      对了,写出来后一直是wa,很费解,出数据也没问题,long long也开了,就是不对。后来发现,对于long long类型的ans我初始化的时候仍然用的2147483647,所以就错了。。改大一点就A掉了···

      

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <vector>
     6 using namespace std;
     7 typedef long long LL;
     8 const int maxn=200000+10;
     9 const int INF=2147483647;
    10 
    11 vector<int>G[maxn];
    12 LL child[maxn],dep[maxn],f[maxn];
    13 int T,n,a,b;
    14 LL ans;
    15 void dfs1(int u,int fa){
    16     for(int i=0;i<G[u].size();i++){
    17         int v=G[u][i];
    18         if(v!=fa){
    19             dep[v]=dep[u]+1;
    20             dfs1(v,u);
    21             child[u]+=child[v];
    22         }
    23     }
    24     return;
    25 }
    26 int dis[maxn];
    27 void dfs(int u,int fa){
    28     dis[dep[u]]=u;
    29     if(fa!=-1&&fa!=1){
    30         f[u]=f[fa]+child[dis[dep[u]/2+1]]-2*child[u];
    31     }
    32     if(fa==1)
    33         f[u]=f[fa];
    34     for(int i=0;i<G[u].size();i++){
    35         int v=G[u][i];
    36         if(v!=fa){
    37             dfs(v,u);
    38         }
    39     }
    40     return;
    41 }
    42 
    43 int main(){
    44     scanf("%d",&T);
    45     for(int t=1;t<=T;t++){
    46         scanf("%d",&n);
    47         for(int i=1;i<=n;i++)G[i].clear();
    48         for(int i=1;i<n;i++){
    49             scanf("%d%d",&a,&b);
    50             G[a].push_back(b);
    51             G[b].push_back(a);
    52         }
    53         for(int i=1;i<=n;i++)child[i]=1;
    54         dep[1]=0;
    55         dfs1(1,-1);
    56         for(int i=2;i<=n;i++)f[i]=INF;;
    57         f[1]=0;
    58         for(int i=1;i<=n;i++)f[1]+=dep[i];
    59         //cout<<f[1]<<endl;
    60         dfs(1,-1);
    61         ans=1e14;
    62         for(int i=1;i<=n;i++)ans=min(ans,f[i]);
    63         printf("%lld
    ",ans);
    64         /*for(int i=1;i<=n;i++){
    65             printf("%d %d
    ",i,f[i]);
    66         }*/
    67     }
    68 return 0;
    69 }
    View Code

     

  • 相关阅读:
    redis使用基础(一) ——Redis基本概述与安装配置
    Linux学习闲谈(三) ——SVN用法及切版本与合版本
    Linux学习闲谈(二) ——SVN版本控制拾遗
    Linux学习闲谈(一)——Shell基本操作与命令
    linux1
    git命令
    ubuntu
    laradock
    实用工具
    grumphp在docker里问题
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/8932367.html
Copyright © 2020-2023  润新知