【每日一题】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][x1]

然后考虑统计答案,以 uLCA 的两个节点,肯定不能在u 的同一个儿子里,所以转移的过程中, f[u][0/1] 表示已经当前已经计算过得儿子造成的贡献,对于一个新的儿子 vans+=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 @   RioTian  阅读(62)  评论(1编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 全程不用写代码,我用AI程序员写了一个飞机大战
历史上的今天:
2020-04-28 小数在内存中是如何存储的?
2020-04-28 #2083:简易版之最短距离(水题)
点击右上角即可分享
微信分享提示