Here is an Easy Problem of Zero-chan

这篇博客讨论了一种针对根为1的树的问题,涉及计算每个节点与其他节点的最近公共祖先(LCA)编号相乘后产生后缀0的个数。通过分析2和5的质因子,作者提出了一个DFS算法,首先计算每个节点的子节点数量,然后再次DFS以传播贡献,从而得到每个节点的答案。博客提供了完整的C++代码实现。
摘要由CSDN通过智能技术生成

登录—专业IT笔试面试备考平台_牛客网

题目大意:有一棵n个点的根为1的树,对于每个点求这个点与其他每个点的lca的编号连续相乘后与多少个后缀0

思路:因为只有2和5相乘才会有后缀0,所以只有质因子中有2或5的点作为Lca才有贡献,而且会贡献给当前点的所有子节点,对他的一个相邻的子节点的贡献为当前贡献+自己含有的2/5的个数*(当前点子节点数-下一个点子节点数),所以我们首先dfs遍历每个点,求出所有点的子节点的数量(包括自己),然后再dfs,同时维护当前的2和5的贡献,每个点的答案等于2的贡献加当前点有几个2因子乘以当前点字节点数和对5进行同样计算的最小值,

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
bool vis[N];
vector<int>g[N];
int sonnum[N];
int get2(int x)
{//计算x有多少质因子2
    int ret = 0;
    while (x%2==0)
    {
        x >>= 1;
        ret++;
    }
    return ret;
}
int get5(int x)
{//计算x有多少质因子5
    int ret = 0;
    while (x %5==0)
    {
        x /= 5;
        ret++;
    }
    return ret;
}
void dfs(int u)
{//计算每个点的子节点数
    vis[u] = 1;
    for (int i = 0; i < g[u].size(); i++)
    {
        int v = g[u][i];
        if (!vis[v])
        {
            dfs(v);
            sonnum[v]++;//帮下层点记录它自己
            sonnum[u] += sonnum[v];//接收下层的子节点数
        }
    }
}
long long ans[N];
bool vis2[N];
void dfs2(int u, int cn2, int cn5)
{//当前点,2的贡献,5的贡献
    vis2[u] = 1;
    ans[u] = min(cn2 + get2(u) * sonnum[u], cn5 + get5(u) * sonnum[u]);
//当前点的答案就是之前的贡献加上自己的贡献,取2和5的最小值
    for (int i = 0; i < g[u].size(); i++)
    {
        int v = g[u][i];
        if (!vis2[v])
        {
            dfs2(v, cn2+get2(u) * (sonnum[u] - sonnum[v]), cn5 + get5(u) * (sonnum[u] - sonnum[v]));//传给下一层的贡献就是当前贡献+当前点因子数*(当前点字节点数-下一个点子节点数)
        }       
    }
}
int main()
{
    int n, q;
    cin >> n >> q;
    for (int i = 1; i <= n - 1; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);//邻接表存图
    }
     
    dfs(1);    
    sonnum[1]++;//1要加上自身    
    dfs2(1, 0, 0);
    for (int i = 1; i <= q; i++)
    {
        int x;
        scanf("%d", &x);
        printf("%lld\n", ans[x]);
    }
    return 0;
}

然后将每个点的贡献向下传递

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timidcatt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值