2013 Multi-University Training Contest 10
有一颗树, 选出3个点。 不在同一条路径上的集合数。
树形DP做遍DFS即可
分别考虑
A,B分别位于cur的不同儿子,C在cur的祖先
A,B,C分别位于cur的不同儿子
#include "stdio.h"
#include "string.h"
#include "vector"
#pragma comment(linker, "/STACK:16777216")
using namespace std;
vector<int>map[100010];
__int64 ans;
__int64 dp[100010],cnt[100010];
int n;
__int64 cal(int cur,int pre)
{
int i;
for (i=0;i<map[cur].size();i++)
if (map[cur][i]!=pre)
cnt[cur]+=cal(map[cur][i],cur);
cnt[cur]++;
return cnt[cur];
}
__int64 dfs(int cur,int pre)
{
int i;
for (i=0;i<map[cur].size();i++)
if (map[cur][i]!=pre)
{
ans+=dp[cur]*cnt[map[cur][i]]*(n-cnt[cur]); // A,B分别位于cur的不同儿子,C在cur的祖先
ans+=dp[cur]*cnt[map[cur][i]]*(cnt[cur]-1-dp[cur]-cnt[map[cur][i]]); //A,B,C分别位于cur的不同儿子
dp[cur]+=dfs(map[cur][i],cur);
}
dp[cur]++;
return dp[cur];
}
int main()
{
int i,a,b;
while (scanf("%d",&n)!=EOF)
{
for (i=1;i<=n;i++)
map[i].clear();
for (i=2;i<=n;i++)
{
scanf("%d%d",&a,&b);
map[a].push_back(b);
map[b].push_back(a);
}
ans=0;
memset(cnt,0,sizeof(cnt));
memset(dp,0,sizeof(dp));
cal(1,-1);
dfs(1,-1);
printf("%I64d\n",ans);
}
return 0;
}