洛谷 P4178 Tree 题解 点分治

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 1n4×104
  • 1 ≤ u , v ≤ n 1\leq u,v\leq n 1u,vn
  • 0 ≤ w ≤ 1 0 3 0\leq w\leq 10^3 0w103
  • 0 ≤ k ≤ 2 × 1 0 4 0\leq k\leq 2\times 10^4 0k2×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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/578534.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

idea 通过maven构建无法使用@SpringBootApplication

问题描述 SpringBootApplication标红&#xff0c;没有提示&#xff0c;无法启动springboot使用maven构建。通过idea的标准版本构建 原因 springboot构建启动依赖spring-boot-maven-plugin idea的标准版本没有指定构建版本&#xff0c;然后在springboot-parent里面没有指定默…

(已解决)PyQT5问题:控件和背景色同色,如何解决?

一、问题复现 难看到吐是不是 二、解决方案 拖动一个widget&#xff0c;设置其背景色&#xff0c;并且右键放到最后一层 三、解决结果 如上图所示 四、问题原因 直接在窗体右键设置背景色&#xff0c;由于Form是父类&#xff0c;即其下所有控件都与其同色&#xff0c;即使…

知识在人工智能中的核心作用:连接主义与符号主义的交融

知识在人工智能中的核心作用&#xff1a;连接主义与符号主义的交融 一、连接主义与深度学习的崛起二、感知与认知&#xff1a;AI的双眼与大脑三、知识的多元表示与处理四、符号主义与知识工程的实践五、知识在AI中的核心地位六、AI的具体应用案例分析七、知识图谱&#xff1a;认…

Linux多线程(一) 线程的创建与控制

一、线程概述 线程是轻量级的进程&#xff08;LWP&#xff1a;light weight process&#xff09;&#xff0c;在Linux环境下线程的本质仍是进程。在计算机上运行的程序是一组指令及指令参数的组合&#xff0c;指令按照既定的逻辑控制计算机运行。操作系统会以进程为单位&#…

element-ui et -i 编译默认主题报错:ReferenceError: primordials is not defined

报错信息如下 fs.js:40 } primordials;^ ReferenceError: primordials is not defined导致这个问题的原因&#xff1a;node和gulp版本冲突&#xff01;&#xff01; 我使用的是node 14版本 解决方法&#xff1a; 看了好几个帖子&#xff0c;都推荐使用node 11.15.0版本&am…

css中新型的边框设置属性border-block

border-block 是 CSS 中的一个属性&#xff0c;主要用于在样式表中一次性设置元素的逻辑块向边框的属性值。这个属性是简写属性&#xff0c;可以同时设置 border-block-width、border-block-style 和 border-block-color。其中&#xff0c;border-block-start 用于设置元素的开…

物联网应用技术综合实训室解决方案

一、背景 随着物联网技术的快速发展和广泛应用&#xff0c;物联网产业已经成为新的经济增长点&#xff0c;对于推动产业升级、提高社会信息化水平具有重要意义。因此&#xff0c;培养具备物联网技术应用能力的高素质人才成为了迫切需求。 传统的教育模式往往注重理论教学&…

新科技辅助器具赋能视障生活:让盲人出行融入日常

随着科技日新月异的发展&#xff0c;一款名为蝙蝠避障专为改善盲人日常生活的盲人日常生活辅助器具应运而生&#xff0c;它通过巧妙整合实时避障与拍照识别功能&#xff0c;成功改变了盲人朋友们的生活格局&#xff0c;为他们提供了更为便捷、高效的生活体验。 这款非同…

DevOps(十五)如何创建参数化的Jenkins Job

一、Jenkins参数化 在Jenkins中创建参数化的Job允许你在构建过程中动态输入一些值&#xff0c;这样可以让构建过程更加灵活和通用。以下是创建参数化Jenkins Job的步骤&#xff1a; 1、 创建新的Job 登录到Jenkins控制台。点击左侧的“新建任务”或“Create new jobs”。输入…

RocketMQ 部署

RocketMQ 部署 1、安装依赖&#xff08;Java&#xff09; [rootMicroservices ~]# mkdir -p /data/businessServer/ [rootMicroservices ~]# cd /data/businessServer/# 获取安装包&#xff08;下载较慢&#xff09; [rootMicroservices businessServer]# wget https://githu…

【Redis 开发】(Feed流的模式,GEO数据结构,BitMap,HyperLogLog)

Redis FeedTimeline GEOBitMapHyperLogLog Feed Feed流产品有两种常见模式: Timeline:不做内容筛选&#xff0c;简单的按照内容发布时间排序&#xff0c;常用于好友或关注。例如朋友圈 优点:信息全面&#xff0c;不会有缺失。并且实现也相对简单 缺点:信息噪音较多&#xff0c…

「51媒体」城市推介会,地方旅游推荐,怎么做好媒体宣传

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 城市推介会和地方旅游推荐是城市形象宣传的重要组成部分&#xff0c;通过有效的媒体宣传可以提升城市的知名度和吸引力。&#xff1a; 一&#xff0c;活动内容层面&#xff1a; 突出亮点…

公认最好的随身WiFi的格行5G随身WiFi真实测评!格行5G和纽曼5G随身WiFi哪个好?5G随身WiFi推荐第一名

随着5G信号基站的铺设逐渐完善&#xff0c;各大通讯移动公司也都适时的推出了属于自己的5G随身WiFi。其中老牌企业纽曼与格行的5G随身WiFi最受大家的欢迎。那么二者到底谁才是5G设备中的王者呢&#xff1f;今天就做一个全面测评。 一、首先是颜值党们最为关注的外观问题 纽曼5…

Java中Synchronized的锁升级

锁升级过程 当JVM启动后&#xff0c;一个共享资源对象直到有线程第一个访问时&#xff0c;这段时间内是处于无锁状态&#xff0c;对象头的Markword里偏向锁标识位是0&#xff0c;锁标识位是01。 Tips&#xff1a;当一个共享资源首次被某个线程访问时&#xff0c;锁就会从无锁状…

记录AE学习查漏补缺(持续补充中。。。)

记录AE学习查漏补缺 常用win下截图WinShifts导入AI/PS工程文件将图层上移一个位置或者下移一个位置展示/关闭图层标线/标度放大面板适应屏幕大小 CtrlAltF 关键帧熟记关键参数移动锚点位置加选一个关键参数快速回到上下一帧隐藏/显示图层关键帧拉长缩短关键帧按着鼠标左键不松手…

新款闯关游戏制作

目前制作4关, cpp. #include "c.h" #include "Level1.h" using namespace std; int main() {srand(time(0)); initgraph(600, 600); BeginBatchDraw();IMAGE a; loadimage(&a, _T("1.jpg")); putimage(0, 0, &a);setbkmode(TRANSPAREN…

【Vue】如何创建一个Vue-cli程序

一、准备工作 1、下载Node.js 官网地址 https://nodejs.org/en 2、查看版本 cmd下通过node-v,查看版本号&#xff1b; cmd下通过npm-v,查看是否打印版本号。 3、安装淘宝加速器 npm install cnpm -g 4、安装Vue-cli cnpm install vue-cli -g 二、创建Vue程序 1、创建一个V…

【数据分析面试】32.矩阵元素求和 (Python: for…in…语句)

题目&#xff1a;矩阵元素求和 &#xff08;Python) 假设给定一个整数矩阵。你的任务是编写一个函数&#xff0c;返回矩阵中所有元素的和。 示例 1&#xff1a; 输入&#xff1a; matrix [[1, 2, 3], [4, 5, 6], [7, 8, 9]]输出&#xff1a; matrix_sum(matrix) -> 45…

Android 12 Starting window的添加与移除

添加&#xff1a; 04-13 16:29:55.931 2944 7259 D jinyanmeistart: at com.android.server.wm.StartingSurfaceController.createSplashScreenStartingSurface(StartingSurfaceController.java:87) 04-13 16:29:55.931 2944 7259 D jinyanmeistart: at com.android.server.wm.…

记录些 LLM 常见的问题和解析

1、提示校准为什么有助于减轻基于提示的学习中的偏见? 提示校准包括调整提示&#xff0c;尽量减少产生的输出中的偏差。 其他&#xff1a;微调修改模型本身&#xff0c;而数据增强扩展训练数据&#xff0c;梯度裁剪防止在训练期间爆炸梯度。 2、是否需要为所有基于文本的LL…
最新文章