链接: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;
}