NC201400 树学题解

树学

https://ac.nowcoder.com/acm/problem/201400

一.题解

​ 这道题又是一道换根dp板子题,代码结构与 Accumulation Degree 这道题基本一致,唯一不同的就是转移了【不过转移的时候,因为方程的原因不需要特殊考虑叶节点】

​ 我们先套路的设表示以为根的子树中所有点的深度和,现在,我们来想想转移。

​ 我们发现,如果我们要从的一个儿子v转移到i的话,以v为根的子树中的所有节点的深度都加了1,现在我们就不能够直接求值了,怎么办呢?很简单,我们发现,既然以v为根的子树中的所有节点的深度都加了1,那么,一共增加的值,不就正好是以v为根的子树中节点的个数嘛?

​ 所以,我们只需要再维护一个以i为根的子树的大小即可

​ 那么,我们就可以很简单的推出转移:

​ 这样,我们一遍dfs就可以求出所有了!

​ 现在,我们考虑换根dp

​ 我们假设将根换成了它的一个儿子,那么,同样的,改变的只是的子树,我们将这个"影响"修改一下即可~

​ 首先,(减去v的贡献)

​ 然后,(修改两个点的子树大小)

​ 最后,(加上i的贡献)

​ 为什么是这个顺序呢?因为修改的时候,必须和以前一样(因为我们是从这两个值转移过来的),然后要修改的话,又必须是修改后,没加v的贡献的值,所以,这样安排修改顺序是很好的。(当然,你非要用其他顺序的话,我也无话可说,只是要注意修改的方法有可能会不同)

​ 最后,我们每次统计下以任意点为根时的值的最小值即可~

​ 代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+1;
struct node{
    int v,nex;
}t[N<<1];
int dp[N],siz[N];
int las[N],len,ans=1e17;
inline void add(int u,int v){
    t[++len]=(node){v,las[u]},las[u]=len;
}
inline void dfs1(int now,int fa){
    siz[now]=1;
    for(int i=las[now];i;i=t[i].nex){
        int v=t[i].v;
        if(v!=fa){
            dfs1(v,now);
            siz[now]+=siz[v];
            dp[now]+=(dp[v]+siz[v]);
        }
    }
}
inline void dfs2(int now,int fa){
    ans=min(ans,dp[now]);
    for(int i=las[now];i;i=t[i].nex){
        int v=t[i].v;
        if(v!=fa){
            int pas1=siz[now],pas2=siz[v];
            int Pas1=dp[now],Pas2=dp[v];//继续偷懒
            dp[now]-=(dp[v]+siz[v]);
            siz[now]-=siz[v];siz[v]+=siz[now];
            dp[v]+=(dp[now]+siz[now]);
            dfs2(v,now);
            siz[now]=pas1,siz[v]=pas2;
            dp[now]=Pas1,dp[v]=Pas2;
        }
    }
}
signed main(){
    int n;
    scanf("%lld",&n);
    for(int i=1;i<n;++i){
        int u,v;
        scanf("%lld%lld",&u,&v);
        add(u,v),add(v,u);
    }
    dfs1(1,1);dfs2(1,1);
    printf("%lld",ans);
    return 0;
}

二.闲话

​ 其实一开始,我变量都开的是int,然而,交上去后,算了下,每次的贡献最大可以达到水平【链】,于是发现很可能爆int,于是,我马上改成long long,然后,改完后正准备提交。。。

​ 恭喜通过~

​ 我:???

全部评论

相关推荐

11-04 19:05
已编辑
东莞城市学院 单片机
不知道怎么取名字_:你这个要实习两年?哪有这么久的,感觉就是即使你毕业了,但还按实习的话,是不是不用给你缴社保公积金啥的
点赞 评论 收藏
分享
专业嗎喽:个人信息名字太大,合到电话邮箱那一栏就行,有党员写过党,剩下其他全删,站空太大了 把实习经历丰富,放最前面,然后是个人评价,技能之类的,然后是学校信息。项目经历最后面,可以就选一个自己擅长的。 现在是学校不是92就扣分的,没必要放前面。 然后现在看重实习经历>竞赛经历(校园经历)>课程项目经历
点赞 评论 收藏
分享
评论
4
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务