leetcode.2846. 边权重均等查询【lca+树形dp】

原题链接:2846. 边权重均等查询

题目描述:

现有一棵由 n 个节点组成的无向树,节点按从 0 到 n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ui, vi, wi] 表示树中存在一条位于节点 ui 和节点 vi 之间、权重为 wi 的边。

另给你一个长度为 m 的二维整数数组 queries ,其中 queries[i] = [ai, bi] 。对于每条查询,请你找出使从 ai 到 bi 路径上每条边的权重相等所需的 最小操作次数 。在一次操作中,你可以选择树上的任意一条边,并将其权重更改为任意值。

注意:

  • 查询之间 相互独立 的,这意味着每条新的查询时,树都会回到 初始状态 。
  • 从 ai 到 bi的路径是一个由 不同 节点组成的序列,从节点 ai 开始,到节点 bi 结束,且序列中相邻的两个节点在树中共享一条边。

返回一个长度为 m 的数组 answer ,其中 answer[i] 是第 i 条查询的答案。

输入输出描述:

示例 1:

输入:n = 7, edges = [[0,1,1],[1,2,1],[2,3,1],[3,4,2],[4,5,2],[5,6,2]], queries = [[0,3],[3,6],[2,6],[0,6]]
输出:[0,0,1,3]
解释:第 1 条查询,从节点 0 到节点 3 的路径中的所有边的权重都是 1 。因此,答案为 0 。
第 2 条查询,从节点 3 到节点 6 的路径中的所有边的权重都是 2 。因此,答案为 0 。
第 3 条查询,将边 [2,3] 的权重变更为 2 。在这次操作之后,从节点 2 到节点 6 的路径中的所有边的权重都是 2 。因此,答案为 1 。
第 4 条查询,将边 [0,1]、[1,2]、[2,3] 的权重变更为 2 。在这次操作之后,从节点 0 到节点 6 的路径中的所有边的权重都是 2 。因此,答案为 3 。
对于每条查询 queries[i] ,可以证明 answer[i] 是使从 ai 到 bi 的路径中的所有边的权重相等的最小操作次数。

示例 2:

输入:n = 8, edges = [[1,2,6],[1,3,4],[2,4,6],[2,5,3],[3,6,6],[3,0,8],[7,0,2]], queries = [[4,6],[0,4],[6,5],[7,4]]
输出:[1,2,2,3]
解释:第 1 条查询,将边 [1,3] 的权重变更为 6 。在这次操作之后,从节点 4 到节点 6 的路径中的所有边的权重都是 6 。因此,答案为 1 。
第 2 条查询,将边 [0,3]、[3,1] 的权重变更为 6 。在这次操作之后,从节点 0 到节点 4 的路径中的所有边的权重都是 6 。因此,答案为 2 。
第 3 条查询,将边 [1,3]、[5,2] 的权重变更为 6 。在这次操作之后,从节点 6 到节点 5 的路径中的所有边的权重都是 6 。因此,答案为 2 。
第 4 条查询,将边 [0,7]、[0,3]、[1,3] 的权重变更为 6 。在这次操作之后,从节点 7 到节点 4 的路径中的所有边的权重都是 6 。因此,答案为 3 。
对于每条查询 queries[i] ,可以证明 answer[i] 是使从 ai 到 bi 的路径中的所有边的权重相等的最小操作次数。 

提示:

  • 1 <= n <= 1e4
  • edges.length == n - 1
  • edges[i].length == 3
  • 0 <= ui, vi < n
  • 1 <= wi <= 26
  • 生成的输入满足 edges 表示一棵有效的树
  • 1 <= queries.length == m <= 2 * 1e4
  • queries[i].length == 2
  • 0 <= ai, bi < n

解题思路:

首先题目说了每个查询是互不干扰的,所以对于每一个查询只需要单独处理即可,对于每一个查询[a,b],题目要求我们使用最少的修改次数使得a<->b路径上的所有边边权都一样,那么我们只需要先找到这条路径上出现次数最多的边权w,然后将其他边权不等于w的边的权重都修改为w,这样操作就能保证操作次数最少,假设a<->b路径上一共有d条边,那么当前查询最少修改次数就是d-cnt[w],cnt[w]表示边权w出现的次数,那么现在需要做的就是怎么找到出现次数最多的边权出现了多少次,那么最暴力的做法就是将a<->b这条路径上的所有边遍历一遍,这样的时间复杂度为O(n),总共有m次查询,那么这个时候的时间复杂度就是O(n*m),这个题目n=1e4,m=2e4,那么时间就是2e8了,这个时间复杂度就很高了,大概率是过不了了,我们考虑怎么进行优化,首先这是一棵树,每次查询一般是可以优化到log(n)的,这个时候常用的优化方式就应该想到和最近公共祖先(lca)有关了,由于边的权重只有26种,我们可以暴力枚举26种边,看哪种边出现次数最多,那么a<->b之间某种边i出现的次数就是f[a][i]+f[b][i]-f[lca(a,b)][i]*2,通过枚举26种边就可以知道出现次数最多的边的出现次数为多少,lca的时间复杂度为log(n),每次枚举26种边,这样每次查询就优化到了26+log(n),n=1e4,那么log(n)大概就是14,14+26=40,总的时间大概是m*40=2e4*40,时间粗略估计大概就是8e5,这个时间复杂度是可以过的,下面时间复杂度分析处分析的会更仔细。

时间复杂度:bfs预处理时间复杂度为O(m+n*14),dp预处理时间复杂度为O(m+n*26),然后查询的时间复杂度为O(m*(log(n)+26)),综合时间大概为40*m+n*40,时间复杂度为O(40*(n+m)),时间大概是40*(1e4+2e4),大概就是40*3e4,花费时间大概就是1.2e6,这个时间是肯定可以过的。

空间复杂度:空间大概是n*50=1e4*50*4=2e6/1e6=2M,单个测试数据这个空间需求非常低,所以空间是肯定足够的,空间复杂度为O(n),但是n前面的常数为50左右。

cpp代码如下:

const int N=1e4+10,M=N*2;
int f[N][26],fa[N][15];
int h[N],w[M],e[M],ne[M],idx;
int q[N],depth[N];
class Solution {
    void add(int a,int b,int c)
    {
        e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
    }
    void bfs(int root)
    {
        memset(depth,0x3f,sizeof depth);
        int hh=0,tt=0;
        depth[0]=0,depth[root]=1;
        q[0]=root;
        while(hh<=tt)
        {
            int t=q[hh++];
            for(int i=h[t];i!=-1;i=ne[i])
            {
                int j=e[i];
                if(depth[j]>depth[t]+1)
                {
                    depth[j]=depth[t]+1;
                    fa[j][0]=t;
                    q[++tt]=j;
                    for(int k=1;k<=14;k++)
                        fa[j][k]=fa[fa[j][k-1]][k-1];
                }
            }
        }
    }

    void dp(int u,int father)
    {
        for(int i=h[u];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(j==father)continue;
            for(int k=0;k<26;k++)
                f[j][k]=f[u][k];
            f[j][w[i]]++;
            dp(j,u);
        }

    }

    int lca(int a,int b)
    {
        if(depth[a]<depth[b])swap(a,b);
        for(int k=14;k>=0;k--)
            if(depth[fa[a][k]]>=depth[b])
                a=fa[a][k];
        if(a==b)return a;
        for(int k=14;k>=0;k--)
            if(fa[a][k]!=fa[b][k])
            {
                a=fa[a][k];
                b=fa[b][k];
            }
        return fa[a][0];
    }
public:
    vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
        //初始化
        for(int i=0;i<n+5;i++)h[i]=-1;
        idx=0;
        //建图
        for(int i=0;i<n-1;i++)
        {
            int u=edges[i][0],v=edges[i][1],w=edges[i][2];
            //将点的编号由0~n-1变为1~n,将边的权重由1~26变为0~25
            u++,v++,w--;
            add(u,v,w),add(v,u,w);
        }

        //题目是无向树,没有规定根节点,我们随便选一个根节点就行,这里我选的1号结点为根节点
        //bfs预处理lca中的depth数组和f数组
        bfs(1);

        //dp预处理
        //f[i][j]表示根节点到i号结点上边权为j的边出现的次数
        dp(1,-1);

        vector<int>ans;
        //处理每一次询问
        for(auto que:queries){
            int u=que[0]+1,v=que[1]+1;  //点的编号变化了,这里跟着变化
            int p=lca(u,v);
            int d=depth[u]+depth[v]-depth[p]*2;  //u,v之间总的边数
            int res=d;
            //枚举26种边
            /*
                d表示u,v之间总的边数,f[u][k]+f[v][k]-f[p][k]*2)表示
                u,v之间边权为k的边出现的次数.
                那么d-f[u][k]+f[v][k]-f[p][k]*2)表示需要修改的边数,
                用来更新答案
            */
            for(int k=0;k<26;k++)
                res=min(res,d-(f[u][k]+f[v][k]-f[p][k]*2));
            ans.push_back(res);
        }
        //输出答案
        return ans;
    }
};

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

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

相关文章

微服务-微服务Alibaba-Nacos注册中心实现

1. 系统架构的演变 俗话说&#xff0c; 没有最好的架构&#xff0c;只有最合适的架构。 微服务架构也是随着信息产业的发展而出现的最有普 遍适用性的一套架构模式。通常来说&#xff0c;我们认为架构发展历史经历了这样一个过程&#xff1a;单体架构——> 垂直架构 ——&g…

leetcode 42.接雨水

问题1&#xff1a;怎么算接水量 总的接水量第一列接水量第二列接水量第三列接水量…最后一列接水量 问题2&#xff1a;当前列的接水量怎么计算 当前的接水量min(当前列左边最高的墙x1&#xff0c;当前列右边最高的墙x3&#xff09;- 当前列x2的高度 问题2图解&#xff1a; …

蓝桥杯-sort排序(上)

sort排序 &#x1f388;1.算法说明&#x1f388;2.例题&#x1f52d;2.1例题一&#x1f52d;2.2例题二&#x1f52d;2.3例题三&#x1f52d;2.4例题四&#x1f52d;2.5例题五&#x1f52d;2.6例题六 &#x1f388;1.算法说明 &#x1f50e;对于一个数组&#xff0c;通过对数组中…

新版UI界面影视小程序亲测无问题带详细搭建教程

新版UI界面影视小程序亲测无问题带详细搭建教程 环境php7.0 — fileinfo–redis–sg11 mysql5.5 apache2.4 添加站点php7.0—-创建ftp—-上传后端文件《后端文件修改&#xff0c;/maccms/wxapi/config/dbs.php–修改当前数据库》—-设置ssl—-打开数据库安装cms 安装好后管…

如何写出有效的单元测试?

什么是单元测试 《单元测试的艺术》中对单元测试的定义&#xff1a; 一个单元测试是一段自动化的代码&#xff0c;这段代码调用被测试的工作单元&#xff0c;之后对这个单元的单个最终结果的某些假设进行校验。 单元测试几乎都是用单元测试框架编写的&#xff1b;只要产品代码…

免费数据恢复软件,帮你轻松恢复丢失数据!

“由于我经常会丢失各种文件&#xff0c;因此非常需要一款实用又有效的数据恢复软件&#xff0c;大家有什么推荐的吗&#xff1f;希望能给我出出主意&#xff01;” 随着数字技术的不断发展&#xff0c;数据恢复软件在我们的生活中扮演着越来越重要的角色。当我们的硬盘或其他存…

Bluetooth Device Address(BD_ADDR) - 2

蓝牙核心规范&#xff1a;Core v5.3中关于蓝牙地址的其他说明 Vol 3: Host, Part C: Generic Access Profile 3 User interface aspects 3.2 Representation of Bluetooth parameters 3.2.1 Bluetooth Device Address (BD_ADDR) BD_ADDR 是蓝牙设备使用的地址。在设备发现过…

nav02 学习03 机器人传感器

机器人传感器 移动机器人配备了大量传感器&#xff0c;使它们能够看到和感知周围的环境。这些传感器获取的信息可用于构建和维护环境地图、在地图上定位机器人以及查看环境中的障碍物。这些任务对于能够安全有效地在动态环境中导航机器人至关重要。 机器人的传感器类似人的感官…

单片机学习笔记---独立按键控制LED状态

上一节学习的是独立按键控制LED亮灭 这一节我们先来讲一下按键的抖动&#xff1a; 对于机械开关&#xff0c;当机械触点断开、闭合时&#xff0c;由于机械触点的弹性作用&#xff0c;一个开关在闭合时不会马上稳定地接通&#xff0c;在断开时也不会一下子断开&#xff0c;所以…

Leetcode刷题笔记题解(C++):1971. 寻找图中是否存在路径

思路&#xff1a; 1.建立图集&#xff0c;二维数组&#xff0c;path[0]里面存放的就是与0相连的节点集合 2.用布尔数组来记录当前节点是否被访问过&#xff0c;深度优先会使用到 3.遍历从起点开始能直接到达的点&#xff08;即与起点相邻的点&#xff09;&#xff0c;判断那…

判断给定的字符串s是否为Python的保留关键字keyword.iskeyword(s)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 判断给定的字符串s 是否为Python的保留关键字 keyword.iskeyword(s) [太阳]选择题 请问以下代码输出的结果是&#xff1f; import keyword print("【执行】keyword.iskeyword(for)"…

【蓝桥杯冲冲冲】[NOIP2000 提高组] 方格取数

蓝桥杯备赛 | 洛谷做题打卡day19 文章目录 蓝桥杯备赛 | 洛谷做题打卡day19[NOIP2000 提高组] 方格取数题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题解代码我的一些话 [NOIP2000 提高组] 方格取数 题目背景 NOIP 2000 提高组 T4 题目描述 设有 N N…

PBM模型学习(五)UDF生长模型

DEFINE_PB_GROWTH_RATE(name, cell, thread, d_i) 该UDF在每个时间步开始时执行,只有在时间步开始时,颗粒粒径才会更新,同时才会UDF才会向文件写入数据GR单位是m/sC_PHASE DIAMETER(c,ts):返回颗粒粒径???,ts为颗粒相的线程C_VOF(cell,thread):颗粒相总体积C_PB DISCI(c…

Kotlin快速入门系列2

Kotlin的基本数据类型 Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double 等。不同于 Java 的是&#xff0c;字符不属于数值类型&#xff0c;是一个独立的数据类型。 Java和kotlin数据类型对照如下&#xff1a; Java基本数据类型 Kotlin对象数据类型 数据类…

vue3+naiveUI二次封装的v-model 联动输入框

根据官网说明使用 源码 <template><div class"clw-input pt-3"><n-inputref"input":value"modelValue":type"type":title"title"clearable:disabled"disabled":size"size"placeholder&…

商家转账到零钱使用教程

商家转账到零钱是什么&#xff1f; 使用商家转账到零钱这个功能&#xff0c;可以让商户同时向多个用户的零钱转账。商户可以使用这个功能用于费用报销、员工福利发放、合作伙伴货款或分销返佣等场景&#xff0c;提高效率。 商家转账到零钱的使用场景有哪些&#xff1f; 商家…

(大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量

今天&#xff0c;面试了一家公司&#xff0c;什么也不说先来三道面试题做做&#xff0c;第一题。 那么&#xff0c;我们就开始做题吧&#xff0c;谁叫我们是打工人呢。 题目是这样的&#xff1a; 统计除豪车外&#xff0c;销售最差的车 车辆按批销售&#xff0c;每次销售若干…

IDC机房交换机核心技术与应用指南

IDC机房交换机核心技术与应用指南 ​ 在这个快速发展的数字时代&#xff0c;数据中心作为信息技术的心脏&#xff0c;不仅承载着海量数据的处理、存储和传输&#xff0c;更是支撑着全球企业运营和互联网服务的关键基础设施。在众多构成数据中心的组件中&#xff0c;IDC机房交换…

在autodl训练yolov8时卡在下载字体

1.问题 在autodl训练yolov8到这一步之后会卡住很久 2. 解决办法 Ctric中断后发现是下载Arial字体卡住了&#xff0c;这个字体需要从外网中下载 先手动从链接中下载https://ultralytics.com/assets/Arial.ttf &#xff0c;然后上传到autodl。然后将这个文件移动到/root/.config/…

RabbitMQ问题总结

:::info 使用场景 异步发送&#xff08;验证码、短信、邮件。。。&#xff09;MySQL 和 Redis、ES 之间的数据同步分布式事务削峰填谷… ::: 如何保证消息不丢失 上图是消息正常发送的一个过程&#xff0c;那在哪个环节中消息容易丢失&#xff1f;在哪一个环节都可能丢失 生…