codeforces 1060E Sergey and Subway 树形dp

链接:http://codeforces.com/contest/1060/problem/E

题意: 一棵树,现在在距离为2 的任意两点之间加一条边,问你加完边之后的任意两点之间的距离总和。

思路: 树形dp ,一开始没有想到记录距离。。然后就没有做出来。   sz1[ u ][ 0 / 1] 分别表示u节点的孩子到这个节点距离为偶数和奇数的个数。    sz2[ u ][ 0 /1 ] 表示 分别表示u节点的父亲到这个节点距离为偶数和奇数的个数。  dis1[ u ][ 0/1 ] 表示u节点的孩纸到这个节点的距离为偶数和奇数的距离总和。  dis2[ u ][ 0/1 ] 表示u节点的父亲 到这个节点的距离为偶数和奇数的距离总和。  那么ans 就是对于当前点,  到当前点的偶数距离/2  + ( 奇数距离+ 奇数个数)/2

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 200005;

vector< int >ve[N];
ll sz1[N][2];
ll dis1[N][2];
ll sz2[N][2];
ll dis2[N][2];
int n;

void dfs1(int u,int fa)
{
    sz1[u][0]=1;
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(v==fa) continue;
        dfs1(v,u);
        sz1[u][0]+=sz1[v][1];
        sz1[u][1]+=sz1[v][0];
        dis1[u][0]+=dis1[v][1]+sz1[v][1];
        dis1[u][1]+=dis1[v][0]+sz1[v][0];
    }
}

void dfs2(int u,int fa)
{
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(v==fa) continue;
        sz2[v][0]+=sz2[u][1];
        sz2[v][0]+=(sz1[u][1]-sz1[v][0]);
        dis2[v][0]+=(dis2[u][1]+sz2[u][1]);
        dis2[v][0]+=(dis1[u][1]-(dis1[v][0]+sz1[v][0])+(sz1[u][1]-sz1[v][0]));

        sz2[v][1]+=sz2[u][0];
        sz2[v][1]+=(sz1[u][0]-sz1[v][1]);
        dis2[v][1]+=(dis2[u][0]+sz2[u][0]);
        dis2[v][1]+=(dis1[u][0]-(dis1[v][1]+sz1[v][1])+(sz1[u][0]-sz1[v][1]));

        dfs2(v,u);
    }
}

int main()
{
    int u,v;
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d %d",&u,&v);
        ve[u].push_back(v);
        ve[v].push_back(u);
    }

    dfs1(1,1);
    dfs2(1,1);

    ll ans=0;
    for(int i=1;i<=n;i++){
        ll disou=dis1[i][0]+dis2[i][0];
        ans+=disou/2;
        ll disji=dis1[i][1]+sz1[i][1]+dis2[i][1]+sz2[i][1];
        ans+=disji/2;
    }

    ans/=2;
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/82942729