牛客挑战赛42B 启发式合并

https://ac.nowcoder.com/acm/contest/6944/B

题意

一个有根树模型,根为1,包含点权。
对每个节点u,子树任意LCA(i,j)是u的两点,求最大的GCD(i,j),以及最大情况下ij取法的方案数。

思路

  • 注意到这个题点权的范围和n相同的。
  • 所有数枚举其因子,这些因子放在一个set里,size也不会超过最大数据范围。
  • 统计gcd其实本质就是统计因子。
  • 用一个结构统计子树所有数分解以后因子个数。
  • 计算节点答案就是一些递推累加。
  • 想到启发式合并优化一下,复杂度就差不多了。
  • O ( N ( a i + l o g ( N ) ) ) O(N(\sqrt{a_i} + log(N))) O(N(ai +log(N)))

挺好的启发式合并练手题。

参考代码

vector<int> g[MAXN];
map<ll, ll> p[MAXN];

ll val[MAXN];
ll cnt[MAXN];

void dfs(int u, int f) {
    for (auto v: g[u]) {
        if (v == f) continue;
        dfs(v, u);
        if (p[u].size() < p[v].size()) {
            p[u].swap(p[v]);
        }
        for (auto pi : p[v]) {
            int x = pi.first;
            if (p[u].count(x) == 0) {
                p[u].emplace(pi);
                continue;
            }
            if (x > val[u]) {
                val[u] = x;
                cnt[u] = p[u][x] * p[v][x];
            } else if (x == val[u]) {
                cnt[u] += p[u][x] * p[v][x];
            }
            
            p[u][x] += p[v][x];
        }
    }
//    debug(u, p[u]);
}

void solve(int kaseId = -1) {
    int n;
    cin >> n;
    for (int i = 2, u, v; i <= n; ++i) {
        cin >> u >> v;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }

    for (ll i = 1, ai; i <= n; ++i) {
        cin >> ai;
        for (ll j = 1; j * j <= ai; ++j) {
            if (ai % j == 0) {
                p[i].emplace(j, 1);
                p[i].emplace(ai / j, 1);
            }
        }
    }
    dfs(1, -1);
    for (int i = 1; i <= n; ++i) {
        cout << val[i] << " " << cnt[i] << endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值