hdu4705 Y 简单树形DP 2013多校训练第十场 J题

题意:求一棵树中不在一条链中的三个点的对数。

转化一下,用总对数减去在一条链上的三点对数即可。

考虑经过根节点,然后可能是不同的子树中各选一个;或者是子树中选一个,然后当前节点为根的子树以外的节点选一个。

这样不重不漏

代码简单。

#define maxn 100005

struct node
{
  int v,next;
};
node e[maxn * 2 ];
int head[maxn];
int cnt ;
i64 ans ;
i64 sum ;
i64 sz[maxn];
i64 n ;
void init()
{
  memset(head,-1,sizeof(head));
  cnt = 0 ;
}
void add(int u,int v)
{
  e[cnt].v = v ;
  e[cnt].next = head[u];
  head[u] = cnt ++ ;
  return ;
}
void dfs(int u,int fa)
{
  for(int i = head[u] ;i != -1 ;i = e[i].next)
  if(e[i].v != fa)
  {
    dfs(e[i].v,u);
    ans = ans + sz[u] * sz[e[i].v];
    sz[u] = sz[u] + sz[e[i].v];
  }
  sz[u] ++ ;
  ans = ans + (n - sz[u]) * (sz[u] - 1);
  return ;
}
int main()
{
  int u,v;
  while(scanf("%I64d",&n)!=EOF)
  {
    init();
    for(int i = 0; i < n - 1; i ++)
    {
      scanf("%d%d",&u,&v);
      add(u,v);
      add(v,u);
    }
    for(int i = 1 ;i <= n ; i++ ) sz[i] = 0 ;
    ans = 0 ;
    dfs(1,0);
    sum = n * (n - 1) * (n - 2 ) / 6 ;
    ans = sum - ans ;
    printf("%I64d
",ans);
  }
    return 0;
}
View Code

最近刷了写树形DP,好像多了呢