【每日一题】16.Treepath (LCA + DP)

补题链接:Here

题意总结:寻找有多少条两个点之间偶数路径

看完题,很容易想到在树型中,同一层的节点必然是偶数路径到达,还有就是每隔两层的节点一样可以到达,所以我就理所应当的写了如下代码

using ll    = long long;
const int N = 1e5 + 10;
vector<int> e[N], deg(N);
int dep[N], Siz[N];
int Mdep = -1;
void dfs(int u, int fa) {
    for (int v : e[u]) {
        if (v == fa) continue;
        dep[v] = dep[u] + 1;
        Mdep   = max(Mdep, dep[v]);
        Siz[dep[v]]++;
        dfs(v, u);
    }
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
        deg[v]++;
    }
    int root = 0;
    for (int i = 1; i <= n && !root; ++i)
        if (!deg[i]) root = i;
    dep[root] = 1, Siz[1] = 1;
    dfs(root, -1);
    ll ans = 0;
    for (int i = 1; i <= Mdep; ++i) {
        ans += Siz[dep[i]] * (Siz[dep[i]] - 1) / 2;
        for (int j = i + 2; j <= Mdep; j += 2)
            ans += Siz[dep[i]] * Siz[dep[j]];
    }
    cout << ans << "\n";
}

然后就GG了,通过率为 \(0\%\)

WA之后重新理解一下题意,发现这个就是一道枚举起点和终点的 \(LCA\) ,然后将他们两两组合即可。

具体的,设 \(f[i][0/1]\)表示以 \(i\) 为根的子树中,与根节点 \(i\) 的距离为偶数(0)奇数(1)的点的数量。

转移方程:\(f[u][x] += f[v][x ⊗ 1]\)

然后考虑统计答案,以 \(u\)\(LCA\) 的两个节点,肯定不能在\(u\) 的同一个儿子里,所以转移的过程中, \(f[u][0/1]\) 表示已经当前已经计算过得儿子造成的贡献,对于一个新的儿子 \(v\)\(ans += f[u][0]·f[v][1] + f[u][1]·f[v][0]\)

AC 代码:

using ll    = long long;
const int N = 1e5 + 10;
vector<int> e[N];
ll ans = 0, f[N][2];
void dfs(int u, int fa) {
    f[u][0] = 1;
    for (int v : e[u]) {
        if (v == fa) continue;
        dfs(v, u);
        ans += f[v][1] * f[u][0];
        ans += f[v][0] * f[u][1];
        f[u][0] += f[v][1];
        f[u][1] += f[v][0];
    }
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        e[u].push_back(v), e[v].push_back(u);
    }
    dfs(1, 0);
    cout << ans << '\n';
}

顺便一句,以前牛客比赛的数据好水....,连下面这种代码都能过 \(60\%\)

using ll = long long;
ll dp[100010], ans, odd, even, n;
void solve() {
    cin >> n;
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        dp[v] = dp[u] + 1;
        ans += (dp[v] & 1 ? even++ : ++odd);
    }
    cout << ans << "\n";
}
posted @ 2021-04-28 11:12  Koshkaaa  阅读(58)  评论(1编辑  收藏  举报