题意:

给定一棵n个节点的树,求偶数长度路径的数量。

Solution1:

考虑树的深度对距离的影响,可以发现,深度奇偶性相同的点之间的距离总是偶数。

证明:我们先将深度更大的点走到和另一个点深度相同,显然需要偶数步,然后两个点同时移动到最近公共节点,可知所用的步数是相同的,加起来也是偶数。

Code

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;

int n, idx, h[N], dep[N];

struct Node {
  int to, next;
} E[N];

void add(int a, int b) { E[idx].to = b, E[idx].next = h[a], h[a] = idx++; }

void dfs(int u, int fa) {
  dep[u] = dep[fa] + 1;
  for (int i = h[u]; ~i; i = E[i].next) {
    int v = E[i].to;
    if (v == fa) continue;
    dfs(v, u);
  }
}

int main() {
  memset(h, -1, sizeof(h));
  cin >> n;
  for (int i = 1; i < n; i++) {
    int x, y;
    cin >> x >> y;
    add(x, y);
    add(y, x);
  }
  dfs(1, 0);
  long long odd = 0, even = 0, res;
  for (int i = 1; i <= n; i++) {
    if (dep[i] & 1)
      odd++;
    else
      even++;
  }
  res = odd * (odd - 1) / 2 + even * (even - 1) / 2;
  cout << res << '\n';
  return 0;
}

solution2:

考虑树形dp。 表示从 i 出发,长度为偶数/奇数的路径数。

从子节点到父节点状态转移:


对于 的每一个儿子 ,贡献即为 , dfs回溯时进行合并更新即可。

Code

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;
typedef long long ll;

int n, idx, h[N];
ll res, dp[N][2];

struct Node {
  int to, next;
} E[N];

void add(int a, int b) { E[idx].to = b, E[idx].next = h[a], h[a] = idx++; }

void dfs(int u, int fa) {
  dp[u][0] = 1;
  for (int i = h[u]; ~i; i = E[i].next) {
    int v = E[i].to;
    if (v == fa) continue;
    dfs(v, u);
    res += dp[v][0] * dp[u][1];
    res += dp[v][1] * dp[u][0];
    dp[u][0] += dp[v][1];
    dp[u][1] += dp[v][0];
  }
}

int main() {
  memset(h, -1, sizeof(h));
  cin >> n;
  for (int i = 1; i < n; i++) {
    int x, y;
    cin >> x >> y;
    add(x, y);
    add(y, x);
  }
  dfs(1, 0);
  cout << res << '\n';
  return 0;
}