题目:

给定一棵n个点的树,问其中有多少条长度为偶数的路径。路径的长度为经过的边的条数。x到y与y到x被视为同一条路径。路径的起点与终点不能相同。1<=n<=100000


做法:

设1为根,树形DP求解。
设: 表示以为根的子树中结点的路径为偶数的数量。 表示以为根的子树中结点的路径为奇数的数量。
树上所有路径可以视为经过根节点和不经过根节点两种。而不经过根节点的路径可以看成经过子树上根节点的情况。也就是说我们只需统计经过每棵子树根节点的路径就可以了。
经过根结点的偶数路径的数量 = 偶数配偶数+奇数配奇数的情况。可以一边dfs一边求解。
请看代码。


代码:

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
vector<int> g[N];
int dp[N][2];
ll ans;
void dfs(int u, int p){
    dp[u][0] = dp[u][1] = 0;
    for (int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if (v == p) continue;
        dfs(v, u);
        int odd = dp[v][0]+1, even = dp[v][1];//从结点v的子树上来有odd个奇数路径,有even个偶数路径。
        ans += even+even*dp[u][0]+odd*dp[u][1];//统计经过u的偶数路径数量。
        dp[u][0] += even, dp[u][1] += odd;//更新
    }
}
int main(void){
    IOS;
    int n; cin >> n;
    for (int i = 0; i < n-1; ++i){
        int u, v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    ans = 0;
    dfs(1, 1);
    cout << ans << endl;
    return 0;
}