洛谷 P4178 Tree 题解 点分治

【学习笔记】点分治 整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 点分治 点分治适合处理大规模的树上路径信息问题。 点分治,即基于树上结点的分治,显然我们在处理路径信息问题的时候,普通结点到根节点的路径信息比较容易计算和维护,因此我们考虑将一棵树分治拆分成若干棵子树,将问题从任意结点到结点间的问题转变为结点与根节点之间的问题递归分治解决。 例如在处理树上任意两点间的最短路径距离问题,显然有两种情况 经过根节点的路径。 不经过根节点的路径。 对于第一种路径,有 dis 阅读详情

Tree

题目描述

给定一棵 n n n 个节点的树,每条边有边权,求出树上两点距离小于等于 k k k 的点对数量。

输入格式

第一行输入一个整数 n n n,表示节点个数。

第二行到第 n n n 行每行输入三个整数 u , v , w u,v,w u,v,w ,表示 u u u 与 v v v 有一条边,边权是 w w w。

第 n + 1 n+1 n+1 行一个整数 k k k 。

输出格式

一行一个整数,表示答案。

样例 #1

样例输入 #1

7
1 6 13 
6 3 9 
3 5 7 
4 1 3 
2 4 20 
4 7 2 
10

样例输出 #1

5

数据规模与约定

对于全部的测试点,保证:

  • 1 ≤ n ≤ 4 × 1 0 4 1\leq n\leq 4\times 10^4 1≤n≤4×104。
  • 1 ≤ u , v ≤ n 1\leq u,v\leq n 1≤u,v≤n。
  • 0 ≤ w ≤ 1 0 3 0\leq w\leq 10^3 0≤w≤103。
  • 0 ≤ k ≤ 2 × 1 0 4 0\leq k\leq 2\times 10^4 0≤k≤2×104。

原题

洛谷P4178——传送门

思路

相较于点分治模板题洛谷P3806,本题要求求出距离小于等于 k k k 的点对数量。我的做法是点分治+容斥:对于以某一个重心为根的树中点对的统计,采用将所有点到根节点的距离进行排序,然后用双指针求出距离相加小于等于 k k k 的点对数量,并减去其中两点在同一个子树中的情况(即减去以子节点为根的子树中的点对数量)。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 4e4 + 6;
const int maxk = 2e4 + 6;

int n;

struct edge
{
    int to; // 边的指向
    int w;  // 边权
};

vector<edge> e[maxn];

int _size[maxn]; // 以i为根的子树的结点数
int max_size;    // 求重心时的删除某结点后剩余子树结点个数的最大值的最小值
int sum;         // 当前子树的结点数
int root;        // 当前子树的根
int del[maxn];   // 处理过的子树的根标记为已删除
int dis[maxn];   // 以某个点为根时各个点到根节点的距离
int k;
int ans = 0;

void add_edge(int u, int v, int w) // 加边函数
{
    e[u].push_back({v, w});
}

void get_root(int u, int vis) // 找到重心,以重心为根
{
    int cur_max_num = 0;
    _size[u] = 1;
    for (int i = 0; i < e[u].size(); i++)
    {
        int v = e[u][i].to;
        if (v == vis || del[v])
            continue;
        get_root(v, u);
        _size[u] += _size[v];
        cur_max_num = max(cur_max_num, _size[v]);
    }
    cur_max_num = max(cur_max_num, sum - _size[u]);
    if (cur_max_num < max_size)
    {
        max_size = cur_max_num;
        root = u;
    }
}

void get_distance(int u, int vis, vector<int> &len) // 求子树中各个点到根节点的距离
{
    len.push_back(dis[u]);
    for (int i = 0; i < e[u].size(); i++)
    {
        int v = e[u][i].to;
        if (v == vis || del[v])
            continue;
        dis[v] = dis[u] + e[u][i].w;
        get_distance(v, u, len);
    }
}

int calc_pair_num(vector<int> &a) // 计算点的对数
{
    sort(a.begin(), a.end());
    int res = 0;
    for (int i = 0, j = a.size() - 1; i < a.size(); i++)
    {
        while (j >= 0 && a[i] + a[j] > k)
        {
            j--;
        }
        if (j >= i)
            res += j;
        else
            res += j + 1;
    }
    return res / 2; // 由于双指针统计的时候重复计算点对(a,b)和(b,a),所以需要除以2
}

void count_path(int u) // 统计点对数
{
    del[u] = 1; // 记录以u为根的树已经计算过路径

    vector<int> num;
    num.push_back(0);

    for (int i = 0; i < e[u].size(); i++)
    {
        int v = e[u][i].to;
        if (del[v])
            continue;
        // 离散化存储该子树中所有距离根结点的路径长度
        vector<int> len;
        // 求出子树v的各个结点到根u的距离
        dis[v] = e[u][i].w;
        get_distance(v, u, len);

        ans -= calc_pair_num(len); // 容斥,减去各个子树中的点对个数
        num.insert(num.begin(), len.begin(), len.end());
    }

    ans += calc_pair_num(num); // 加上该树中的点对个数
}

void divide(int u) // 分治
{
    count_path(u); // 计算经过根u的所有路径长度
    // 对u的子树分治
    for (int i = 0; i < e[u].size(); i++)
    {
        int v = e[u][i].to;
        if (del[v])
            continue;
        // 对子树进行分治,要更新sum和max_size为子树的大小
        sum = _size[v];
        max_size = _size[v];
        get_root(v, 0);
        divide(root);
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin >> n;
    int a, b, c; // 连接a和b的边权为c的路径
    for (int i = 1; i <= n - 1; i++)
    {
        cin >> a >> b >> c;
        add_edge(a, b, c);
        add_edge(b, a, c);
    }

    cin >> k;

    sum = n;
    max_size = n;
    get_root(1, 0);    // 寻找重心
    get_root(root, 0); // 通过该重心,更新所有子树的大小
    divide(root);

    cout << ans << '\n';

    return 0;
}
几款开源的自动驾驶仿真平台项目 它被开发为一个虚幻的插件,可以简单地放到任何你想要的虚幻环境中。第一类是基于合成的数据,对环境、感知及车辆进行模拟,这里的感知大多数是图像层面的感知,这类模拟器主要用于感知、规划算法的初步开发上,Carla、AirSim、Udacity self-driving car simulator就属于这类;第二类是基于真实数据的回放,这里的真实数据包括图像、lidar、radar等各种传感器的数据,这类模拟器主要用于测试无人驾驶中信息融合算法以及车辆不同部件的性能,Apollo和Autoware就属于这类。 阅读详情

相关推荐

从科研小白到动物行为分析:我的DeepLabCut 3.0安装与初体验全记录

本文记录了从科研小白到成功安装并使用DeepLabCut 3.0进行动物行为分析的全过程。详细介绍了Anaconda环境配置、CUDA版本选择、DeepLabCut安装步骤及验证方法,并分享了初体验中的实用技巧和跨学科研究心得,为生物研究者提供了AI工具应用的实战指南。

weixin_30235225的博客 402

递归/分治题单(洛谷)

刚写了几道不错的递归题,题目倒是不难,自己实现起来却有点困难,大佬们代码的思路很好,我倒是没想到递归可以这么精妙,递归确实好用啊!

wh233z的博客 1441

Ubuntu20.04安装NVIDIA显卡驱动避坑指南:从.run文件到完美运行

本文详细介绍了在Ubuntu20.04系统上通过.run文件安装NVIDIA显卡驱动的完整流程和避坑技巧。从禁用Nouveau驱动、选择合适显示管理器到处理常见安装问题,提供了一套经过验证的解决方案,帮助用户顺利完成驱动安装并优化性能。

weixin_30776273的博客 603

点分治简介(洛谷P3806)

处理树上路径之间的一些关系时,如果采用暴力,往往时间复杂度不能够接受。而点分治能够很好的解决这一类问题

forezxl的博客 1062

富斯遥控器-ros机器人控制

富斯遥控器-ros机器人手柄控制

zkh7758的博客 1699

gtsam官方文档: The new IMU Factor学习笔记

gtsam官方文档:The new IMU Factor 本文为gtsam imu预积分文档学习笔记,为gtsam基于切向量实现的imu预积分的理论基础。 导航状态 定义导航状态为 Xbn={Rbn,Pbn,Vbn}X^n_b=\{R^n_b,P^n_b,V^n_b\}Xbn​={Rbn​,Pbn​,Vbn​} 上角标n:导航(navigation)坐标系 下角标b:载体(body)坐标系 下文均省略上下标 矢量场与微分方程 对于导航问题我们用如下微分方程描述 X˙(t)=F(t,X)\dot X(t)

南柯一梦的博客 1608

【洛谷P4178】Tree【分块】

题目: 题目链接:https://www.luogu.com.cn/problem/P4178 给你一棵树,以及这棵树上边的距离,问有多少对点它们两者间的距离小于等于kkk。 思路: 这道题是应该加强数据了。。。 当然如果这道题不打算做点分治模板题的话可以不用 O(nn log⁡n)O(n\sqrt n\ \log \sqrt n)O(nn​ logn​)分块在洛谷优秀的O2...

stoorz 370

【PointNet++】使用Open3D对分割后的结果可视化

PointNet++中的局部分割网络预测后是没有可视化文件的,所以需要自己通过编写Open3D或者PCL点云算法去可视化,在本人经过查找翻阅修改后,实现了网络输出点云分割后结果的可视化。已实现推测单个点云,并可视化。

纵马踏花向自由 2453

Poj1741[Tree]题解--点分治||Treap

poj1741

Greninja的博客 667

华为Ascend_toolkit在x86ubuntu安装失败报错。[WARNING] driver package is not installed. If you install in docker

这个报错发生在交叉编译配置Ascend_toolkit环境时,安装Ascend_toolkit安装包的时候发生。[Y/N]Y。

anananajiushiwo的博客 1019

深入剖析 Wenet 下 AISHELL-1 的 run.sh 脚本:从数据准备到模型训练

run.sh脚本用于处理 AISHELL-1 数据集的整个训练和测试流程。我们将逐步分析脚本中的每个部分,包括环境变量、参数设置、各个阶段的执行等。stage: 设置脚本的起始阶段(如数据准备)。stop_stage: 设置脚本的结束阶段。通过对 Wenet 下 AISHELL-1 的run.sh脚本的详细剖析,我们希望你能更好地理解每个步骤的功能及其背后的原理。此脚本不仅为模型训练提供了便利,也为用户自定义和扩展训练流程提供了基础。希望本教程能帮助你顺利完成语音识别项目!

帅小柏的博客 1632

洛谷题单 Part 2.4 分治

分治算法在算法竞赛的应用

Dawn的博客 795

【YOLOv13[基础]】热力图可视化实践 | 脚本升级 | 优化可视化效果 | 论文必备 | GradCAMPlusPlus, GradCAM, XGradCAM, EigenCAM等

本文将进行添加YOLOv13版本的升级版热力图可视化功能的实践,支持图像热力图可视化、优化可视化效果、 可以选择使用GradCAMPlusPlus, GradCAM, XGradCAM, EigenCAM, HiResCAM, LayerCAM, RandomCAM, EigenGradCAM。一个参数即可设置是否显示检测框等。

静谧、淡雅 644

【洛谷】P4178

分治 #树形结构 #双指针。

Antonio915的博客 1003

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

luogu P4178 Tree

题目链接 luogu P4178 Tree 题解 点分治 代码 // luogu-judger-enable-o2 #include<cstdio> #include<algorithm> inline int read() { int x = 0,f = 1 ; char c = getchar(); while(c < ...

agtvo48266的专栏 133

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

省选前的点分治抢救计划

例行的废话: 为什么有这么个东西? 因为沙茶博主没有好好学过点分治,NOIP前讲了几次都是看着题解瞎打了一气混过去的,NOIP之后就没有好好讲的也没有好好做了。 所以点分治水平基本为零,于是尝试在滚粗之前抢救一下,重学点分治(和动态点分治)。 注意是自我抢救,不是教程或者题目汇总,所以完全不建议看这个东西(不会的看了还不会,会了的看了发现都是水题,而且很可能错误百出) (什么,边分治?那...

weixin_30753873的博客 113

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

ESP32上真正的WebAssembly应用:四大嵌入式契约解析

WebAssembly(WASM)作为一种可移植字节码格式,常被误认为开箱即用的跨平台方案;其核心原理是通过线性内存、确定性执行和沙箱机制保障安全与一致性。在资源受限的嵌入式场景中,WASM的技术价值不在于替代原生代码,而在于支持业务逻辑热更新、多语言协同与远程动态升级。然而,要使其真正落地于ESP32等MCU平台,必须突破浏览器环境依赖,完成从虚拟机模型到裸机约束的工程适配——这涉及启动时序对齐FreeRTOS、SRAM级内存静态规划、外设访问的host function安全封装,以及OTA/看门狗/低功

weixin_33908217的博客 398

洛谷P4178 Tree (点分治)

题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k 输出格式: 一行,有多少对点之间的距离小于等于k 输入输出样例 输入样例#1: 7 1 6 13 6 3 9 3 5 7 ...

weixin_30449239的博客 132

点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程—— dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径在重心的子树内就已经相交) 删除重心(打上永久标记),对子树继续处理,转1 求重心是板子,算答案的方法要依题而定,一般都要容斥。 模板题洛谷传送门 calc函数中,头尾两个指针扫的计数方...

a83229442的博客 181

洛谷P4242 树上的毒瘤-树剖+虚树+点分治

传送门 题意: 这棵树上有 n 个节点,每个点的初始颜色为 cicic_i 。 接下来进行 q 个操作: 1.修改树上某个点到另外一个点的简单路径上所有毒瘤的颜色。 2.对于给定的树上某个点集 S ,定义某个点集内的点的权值为: Wi=∑j∈ST(i,j)Wi=∑j∈ST(i,j)W_i=\sum_{j\in S}T(i,j) 其中T(i,j)表示i到j的路径上的颜色的段数 每次指...

Fizzmy的博客 696

洛谷 P4178 Tree 点分治模板题

洛谷 P4178 Tree 题意 给定一棵 nnn 个节点的树,每条边有边权,求出树上两点距离小于等于 kkk 的点对数量。 解法 点分治模板题。 考虑以 uuu 作为路径的lca, uuu 连接了若干子树,遍历每一棵子树,计算出深度,并询问前面子树有多少个点深度小于等于 k−d[i]k-d[i]k−d[i] ,用树状数组维护单点修改区间查询即可。询问结束后把这个子树的答案累加进树状数组。遍历完所有子树后清空答案,注意不能用memset 清空,要在树上遍历来清空,否则复杂度是不对的。 每次枚举的lca 都

bandiaoz的博客 368

洛谷P3806 点分治1

https://www.luogu.com.cn/problem/P3806 时隔一年半复习一下点分治。。。。 点分治模板就是nlogn的,然后内部每次要排序还要二分就是nlog^2n的复杂度。。。。812ms飘过 不过看到网上一些平方求是否有K的组合也过了??? 显然是要先合并值相同的,再枚举一个值为x的,二分找k-x的吧。。。。 #include<bits/stdc++.h&...

binarycopycode 370

点分治(树分治)

介绍: 将原问题分解成若干相同形式,相互独立的子问题,各个击破 一般用来解决有关树上路径的统计和询问 题目: P4178 Tree 给定一棵 n 个节点的树,每条边有边权,求出树上两点距离小于等于 k 的点对数量。 做法: 暴力做法;(O(n2)) 点分治做法: 选择一个点作为分治中心,令其为rt做dfs。对于一条路径path(u,v),其要么经过rt(即lca(u,v) = = rt),要么在某个子树sub(son[rt])中 把问题形式化为: solve(T,rt) = 统计T树中经过rt且长度&lt

qq_35975367的博客 1044

Luogu P4178 Tree (点分治 + 树状数组)

整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Problem 给定一棵 nnn 个节点的树,每条边有边权,求出树上两点距离小于等于 kkk 的点对数量。 Solution 树上路径信息问题显然用点分治。 这道题统计的是树上两点距离小于等于 kkk 的点对数量,我们当然可以先算出距离等于 kkk 的点对数量,然后容斥即可。 但我不想动脑子( 我们显然可以开一个桶 bit[i] 表示距离小于等于 i 的点对的数量。 我们使用树状数组维护即可。 时间复杂度

繁凡さん的博客 539

洛谷 [P3806] 点分治1 (点分治模板)

Link https://www.luogu.org/problemnew/show/P3806 Description  给定一棵有nnn个点的树,询问树上距离为kkk的点对是否存在。 Solution  这是一道点分治的模板题。  点分治一般有以下几种用法: 求路径长度等于或小于等于kkk的点对(路径条数); 路径长度为kkk的倍数; 路径长度为kkk且路径的边数最少; 路径长度对某个数xx...

梧桐 398

P4178 Tree (点分治)

题意: 给定一棵 n 个节点的树,每条边有边权,求出树上两点距离小于等于 k 的点对数量。 题解: 根点分治模板提很相似,只不过这个题目让你去维护小于等于k距离点的个数,这个时候我们还是要用到桶的思想,只不过每次查询查的时小于等于(k-某个值)的个数,对于这个操作,我们可以用一个树状数组来维护即可。 做的时候还是很多方面的小bug,比如说找重心的时候手残…等等 代码: #include<bits/stdc++.h> using namespace std; const int maxn=1e

xxxxxiao123的博客 208
上一篇: 洛谷 P3806 [模板] 点分治 1 题解
下一篇: 洛谷 P3374 [模板] 树状数组 1
bbc_ouo
博客等级 码龄3年 2096粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值