关于没那么启发式的启发式合并写法

本文探讨了真实与虚假的树上启发式合并算法,详细介绍了通过轻儿子和重儿子处理来优化时间与空间复杂度的技术。虚假启发式合并虽然看似不合理,但其时间复杂度表现优秀,代码更简洁,空间复杂度亦有所优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

真实的树上启发式合并:先dfs一遍,处理出轻儿子和重儿子,然后先处理轻儿子,再处理重儿子,最后把轻儿子合并进重儿子。

虚假的树上启发式合并:大的合进小的.jpg

然而虚假的启发式合并的时间复杂度意外的优秀,很意外的能水(稳?)过很多题。

比起真实的启发式合并少了蛮多代码,何乐而不为呢。

同时空间复杂度居然也优化了不少,swap操作让全局map内元素少了非常非常多。

cf600e:

#include<bits/stdc++.h>

using namespace std;
const long long mod = 1e9 + 7;
typedef long long ll;

const int maxn = 1e5 + 5;

int n, u, v, cor[maxn];
ll ans[maxn];
int id[maxn], tot;
unordered_map<int, int> mp[maxn];
map<int, ll> cnt[maxn];
vector<int> G[maxn];

void merge(int &x, int &y) {
    if (mp[y].size() > mp[x].size()) {
        swap(x, y);
    }
    for (auto &e: mp[y]) {
        cnt[x][mp[x][e.first]] -= e.first;
        mp[x][e.first] += e.second;
        cnt[x][mp[x][e.first]] += e.first;
    }
}

void dfs(int x, int fa) {
    id[x] = ++tot;
    mp[id[x]][cor[x]] = 1;
    cnt[id[x]][mp[id[x]][cor[x]]] = cor[x];
    for (int i = 0; i < G[x].size(); ++i) {
        int v = G[x][i];
        if (v == fa) {
            continue;
        }
        dfs(v, x);
        merge(id[x], id[v]);
    }
    ans[x] = cnt[id[x]].rbegin()->second;
}


int main() {
    ios::sync_with_stdio(0);
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> cor[i];
    }
    for (int i = 1; i < n; ++i) {
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, 1);
    for (int i = 1; i <= n; ++i) {
        cout << ans[i] << ' ';
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值