Race 树分治写法

//题意:一棵树有边权,询问一条长度为k的简单路径所需的最小步数
// 思路: 点分治,主要是合并的思路,因为是要求最小步数,所以我们对于每一种长度记最小步数即可
//
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
const int M = 1e6 + 10;
vector<pair<int, int>> e[N];
namespace CenDec {
    int ctr, n, sz[N];
    bool del[N];
    void dfs(int p, int fa = 0) {
        sz[p] = 1;
        int mss = 0;
        for (auto to : e[p]) {
            if (del[to.first] || to.first == fa) continue;
            dfs(to.first, p);
            if (ctr != -1) return;//在子树递归过程中找到重心就即时退出
            mss = max(mss, sz[to.first]);
            sz[p] += sz[to.first];
        }
        mss = max(mss, n - sz[p]);//与根节点之上的那棵子树进行比较
        if (mss <= n / 2) {
            ctr = p;
            sz[fa] = n - sz[p];//更新sz[fa]的值,目的是把重心相邻的所有子树大小重新更新一遍,因为待会我们要
                               //从这个重心向下分治,向下分治的话我们是需要用到相邻子树大小的
        }
    }
    int k, cnt = 1e9;

    map<int, int> depp;
    pair<int, int> temp[2 * N];//第一维记路径长度,第二维记步数
    int cntt;


    void add(int i) {
        if (depp.find(temp[i].first) == depp.end()) depp[temp[i].first] = temp[i].second;
        else depp[temp[i].first] = min(depp[temp[i].first], temp[i].second);
    }
    void dfs2(int p, int fa, int w, int dp) {

        if (w > k) return;//剪枝,同时防止数组访问越界
        if (depp.find(k - w) != depp.end()) {
            cnt = min(cnt, depp[k - w] + dp);
        }
        temp[++cntt] = { w,dp };
        for (auto to : e[p])
            if (!del[to.first] && to.first != fa)
                dfs2(to.first, p, w + to.second, dp + 1);
    }
    
    void run(int p) {
        depp[0] = 0;
        for (auto to : e[p]) {
            if (del[to.first]) continue;
            dfs2(to.first, p, to.second, 1);
            for (int i = 1; i <= cntt; ++i)
                add(i);
            cntt = 0;
        }
        depp.clear();//清空该重心的统计
         
        del[p] = 1;
        for (auto to : e[p]) {
            if (!del[to.first]) {
                n = sz[to.first];//现在要遍历的树是上个重心的子树
                ctr = -1;
                dfs(to.first);
                run(ctr);
            }
        }
    }
    int count(int n0, int k0) {
        n = n0, k = k0; ctr = -1;
        dfs(1);//找重心
        run(ctr);//计算贡献
        if (cnt != 1e9)
            return cnt;
        else return -1;
    }
}
signed main() {
    int n, k; cin >> n >> k;
    for (int i = 1; i <= n - 1; i++) {
        int a, b, c; cin >> a >> b >> c;
        a++, b++;
        e[a].push_back({ b,c });
        e[b].push_back({ a,c });
    }
    cout << CenDec::count(n, k) << endl;
    return 0;
}

 

原文链接: https://www.cnblogs.com/Aacaod/p/17030245.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    Race 树分治写法

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/310051

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 上午11:20
下一篇 2023年2月16日 上午11:20

相关推荐