codeforces 161D Distance in Tree 树形dp
题目链接:
http://codeforces.com/contest/161/problem/D
D. Distance in Tree
memory limit per test 512 megabytes
题意
给你一颗树,每条边长为1,求所有距离为k的顶点对,(u,v)和(v,u)算一对。
题解
树形dp:
dp[i][j]表示与第i个节点距离为j的节点数。
两次dfs:
第一次求以i为根的子树中与i距离为j的节点数dp[i][j]。
第二次求i与不在i的子树中的节点金额距离为j的节点数。
两次加起来就是表示与i节点距离为j的所有的树上节点数。
答案就是sigma(dp[i][k])。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#define lson (o<<1)
#define rson ((o<<1)|1)
#define M (l+(r-l)/2)
using namespace std;
const int maxn=5e4+10;
const int maxm=555;
typedef __int64 LL;
int n,k;
LL dp[maxn][maxm];
vector<int> G[maxn];
void dfs1(int u,int fa) {
dp[u][0]=1;
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v==fa) continue;
dfs1(v,u);
for(int j=0;j+1<=k;j++){
dp[u][j+1]+=dp[v][j];
}
}
}
LL tmp[maxm];
void dfs2(int u,int fa) {
if(fa!=-1){
tmp[0]=dp[fa][0];
for(int j=1;j<=k;j++){
tmp[j]=dp[fa][j]-dp[u][j-1];
}
for(int j=0;j+1<=k;j++){
dp[u][j+1]+=tmp[j];
}
}
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v==fa) continue;
dfs2(v,u);
}
}
int main() {
scanf("%d%d",&n,&k);
memset(dp,0,sizeof(dp));
for(int i=0; i<n-1; i++) {
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,-1);
dfs2(1,-1);
LL ans=0;
for(int i=1;i<=n;i++){
ans+=dp[i][k];
}
printf("%I64d\n",ans/2);
return 0;
}