LC 2846. 边权重均等查询

news2024/11/6 7:09:18

2846. 边权重均等查询

难度: 困难

题目大意:

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

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

注意:

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

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

提示:

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

示例 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 的路径中的所有边的权重相等的最小操作次数。

分析

如果暴力写的话, 那么对于每一个查询,我们要dfs一遍,每一遍存一下路径上的边权得数量,最后用总的数量减去最多的变得数量就是答案,这是一个小贪心的思路,那么考虑一下数据范围,如果暴力写的话,时间复杂度是 O ( n 2 ) O(n^2) O(n2),肯定会超时的,但是也吧暴力写法的代码贴出来。

723 / 733 个通过的测试用例

暴力 dfs (会超时)

class Solution {
public:
    vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
        int m = queries.size();
        vector<int> e(n << 1), ne(n << 1), h(n, -1), w(n << 1), ans(m); // 链式向前星
        int cnt[27], idx = 0;
        
        // add
        function<void(int, int, int)> add = [&](int a, int b, int c) {
            e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
            e[idx] = a, ne[idx] = h[b], w[idx] = c, h[b] = idx ++;
        }; // add
        
        // dfs
        function<bool(int, int, int)> dfs = [&](int u, int b, int fa) {
            if (u == b) {
                return true;
            }
            for (int i = h[u]; ~i; i = ne[i]) {
                int j = e[i];
                if (j == fa) continue;
                if (dfs(j, b, u)) {
                    ++ cnt[w[i]];
                    return true;
                }
            }
            return false;
        }; // dfs
        
        for (int i = 0; i < n - 1; i ++ ) {
            int a = edges[i][0], b = edges[i][1], w = edges[i][2];
            add(a, b, w);
        }
       	
        for (int i = 0; i < m; i ++) {
            memset(cnt, 0, sizeof cnt); // 每次清空数组
            int a = queries[i][0], b = queries[i][1];
            dfs(a, b, -1);
            int res = 0, sum = 0;
            for (int i = 1; i <= 26; i ++) {
                sum += cnt[i];
                res = max(res, cnt[i]);
            }
            ans[i] = sum - res;
        }
        return ans;
    }
};

时间复杂度: O ( n ∗ m ∗ W ) O(n*m*W) O(nmW) (本题 W = 26)

分析

我们可以用最近公共祖先的思想,选定一个根节点,假设是0,那么定义一个cnt[i][w]表示节点i到根节点的路径中边权为w(1 <= w <= 26)的边的数量,那么ij之间边权为w的边数是 t a = c n t [ i ] [ w ] + c n t [ j ] [ w ] − 2 ∗ c n t [ l c a ( i , j ) ] [ w ] t_a = cnt[i][w] + cnt[j][w] - 2 * cnt[lca(i, j)][w] ta=cnt[i][w]+cnt[j][w]2cnt[lca(i,j)][w]lca(i, j)表示节点i和节点j的最近公共祖先, 那么要替换的边数就是
∑ i = 1 26 t i − max ⁡ 1 < = i < = 26 t i \sum_{i = 1}^{26} {t_i} - \max_{1 <= i <= 26}t_i i=126ti1<=i<=26maxti
使用离线算法tarjan算法模板

tarjan + 并查集

class Solution {
public:
    using PII = pair<int, int>;
    vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
        int m = queries.size();
        vector<unordered_map<int, int>> g(n);
        for (auto& e : edges) {
            g[e[0]][e[1]] = e[2];
            g[e[1]][e[0]] = e[2];
        }
        vector<vector<PII>> q(n);   
        for (int i = 0; i < m; i ++ ){
            q[queries[i][0]].push_back({queries[i][1], i});
            q[queries[i][1]].push_back({queries[i][0], i});
        }
        vector<int> lca(m), vis(n), p(n);
        iota(p.begin(), p.end(), 0);
        vector<vector<int>> cnt(n, vector<int>(27));
        function<int(int)> find = [&](int x) {
            if (x != p[x]) p[x] = find(p[x]);
            return p[x];
        };
        function<void(int, int)> tarjan = [&](int u, int fa) {
            if (fa != -1) {
                cnt[u] = cnt[fa];
                ++ cnt[u][g[u][fa]];
            }
            p[u] = u;
            for (auto& e : g[u]) {
                if (e.first == fa) continue;
                tarjan(e.first, u);
                p[e.first] = u;
            }
            for (auto& e : q[u]) {
                if (u != e.first && !vis[e.first]) continue;
                lca[e.second] = find(e.first);
            }
            vis[u] = 1;
        };
        tarjan(0, -1);
        vector<int> res(m);
        for (int i = 0; i < m; i ++ ){
            int sum = 0, mx = 0;
            for (int j = 1; j <= 26;j ++) {
                int t = cnt[queries[i][0]][j] + cnt[queries[i][1]][j] - 2 * cnt[lca[i]][j];
                mx = max(mx, t);
                sum += t;
            }
            res[i] = sum - mx;
        }
        return res;
    }
};

时间复杂度: O ( ( m + n ) × W + m × l o g n ) O((m+n)×W+m×logn) O((m+n)×W+m×logn) (本题 W = 26)

在线lca算法

const int N = 10010;
class Solution {
public:
    int e[N << 1], ne[N << 1], w[N << 1], h[N],  idx;
    int fa[N][15], depth[N];
    int cnt[N][27], cntn[27];
    int q[N];

    void bfs() {
        int hh = 0, tt = 0;
        q[0] = 1;
        memset(depth, 0x3f, sizeof depth);
        depth[0] = 0, depth[1] = 1;
        while (hh <= tt) {
            int t = q[hh ++ ];
            for (int i = h[t]; ~i; i = ne[i]) {
                int j = e[i];
                if (depth[j] > depth[t] + 1) {
                    depth[j] = depth[t] + 1;
                    q[ ++ tt] = j;
                    fa[j][0] = t;
                    for (int k = 1; k <= 14; k ++ )
                        fa[j][k] = fa[fa[j][k - 1]][k - 1];
                }
            }
        }
    }
    // dfs版本
	void dfs_dep(int u, int father) {
        depth[u] = depth[father] + 1;
        fa[u][0] = father;
        for (int i = 1; i <= 14; i ++) 
            fa[u][i] = fa[fa[u][i - 1]][i - 1];
        for (int i = h[u]; ~i; i = ne[i]) {
            if (e[i] != father) {
                dfs_dep(e[i], u);
            }
        }
    }
    
    void add(int a, int b, int c) {
        e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
    }

    void dfs(int u, int fa) {
        memcpy(cnt[u], cntn, sizeof cntn);
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (fa == j) continue;
            cntn[w[i]] ++;
            dfs(j, u);
            cntn[w[i]] -- ;
        }
    }

    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];
    }

    vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
        memset(h, -1,sizeof h);
        for (int i = 0; i < edges.size(); i ++ ) {
            int a = edges[i][0], b = edges[i][1], c = edges[i][2];
            a ++, b ++ ;
            add(a, b, c), add(b, a, c);
        }
        bfs();
        // dfs_dep(1, 0); // dfs_dep版本
        dfs(1, -1);
        vector<int> ans(queries.size());
        for (int i = 0; i < queries.size(); i ++ ) {
            int a = queries[i][0], b = queries[i][1];
            a ++, b ++ ;
            int p = lca(a, b);
            vector<int> s(27);
            for (int j = 1; j <= 26; j ++ )
                s[j] += cnt[a][j] + cnt[b][j] - cnt[p][j] * 2;
            int sum = 0, maxv = 0;
            for (int j = 1; j <= 26; j ++ ) {
                maxv = max(maxv, s[j]);
                sum += s[j];
            }
            ans[i] = sum - maxv;
        }
        return ans;
    }
};

时间复杂度: O ( m l o g n ) O(mlogn) O(mlogn)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI数字人-数字人视频创作数字人直播效果媲美真人

在科技的不断革新下&#xff0c;数字人技术正日益融入到人们的生活中。近年来&#xff0c;随着AI技术的进一步发展&#xff0c;数字人视频创作领域出现了一种新的创新方式——AI数字人。数字人视频通过AI算法生成虚拟主播&#xff0c;其外貌、动作、语音等方面可与真实人类媲美…

element-UI上传文件后valid提示不消失

问题描述&#xff1a;上传文件完成后&#xff0c;必填信息提示不消失 解决方法&#xff1a;在<el-form-item>标签添加show-message属性&#xff0c;字段为空时才显示提示信息 <el-form-item :prop"fileList" :show-message"!form.fileList || !form.f…

命令行启动Android Studio模拟器

1、sdk路径查看&#xff08;打开Android Studio&#xff09; 以上前提是安装的Android Studio并添加了模拟器&#xff01;&#xff01;&#xff01; 2、复制路径在终端进入到 cd /Users/duxi/Library/Android/sdk目录&#xff08;命令行启动不用打开Android Studio就能运行模拟…

C++逆向分析--虚函数(多态的前置)

先理解一件事&#xff0c;在intel汇编层面来说&#xff0c;直接调用和间接调用的区别。 直接调用语法&#xff1a; call 地址 硬编码为 &#xff1a;e8 间接调用语法: call [ ...] 硬编码为: FF 那么在C语法中&#xff0c;实现多态的前提是父类需要实现多态的成员…

跟无神学AI之Prompt

在大模型时代会写prompt变得很重要。 Prompt翻译为中文为提示词&#xff0c;在大模型的特定领域指的是大模型使用者给大模型提交的一种有一定格式的交互命令&#xff0c;让我们看看科大讯飞的大模型给出的答案—— Prompt是一种向人工智能模型提供的输入文本或指令&#xff0…

今日AI大热潮,明日智能风向标

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

YOLO系列(YOLO1-YOLO5)技术规格、应用场景、特点及性能对比分析

文章目录 前言一、YOLOv1-YOLOv5技术规格对比&#xff1a;二、主要应用场景和特点&#xff1a;三、性能对比分析&#xff1a;四、市场应用前景及对不同用户群体的潜在影响&#xff1a;总结 前言 YOLO&#xff08;You Only Look Once&#xff09;系列模型作为一种实时目标检测算…

【数据库学习】pg安装与运维

1&#xff0c;安装与配置 #安装 yum install https:....rpm1&#xff09;安装目录 bin目录&#xff1a;二进制可执行文件目录&#xff0c;此目录下有postgres、psql等可执行程序&#xff1b;pg_ctl工具在此目录&#xff0c;可以通过pg_ctl --help查看具体使用。 conf目录&…

Linux实现:从倒计时到进度条

文章目录 1.回车与换行2.缓冲区的概念3.倒计时4.进度条(第一版无应用场景)5.进度条(第二版有应用场景) 1.回车与换行 2.缓冲区的概念 强制刷新可以使用冲刷函数fflush #include <stdio.h> #include <unistd.h> int main() {printf("I am a \nhandsome man!&q…

HTML - 介绍

一.简介 HTML&#xff0c;超文本标记语言&#xff08;HyperText Markup Language&#xff09;&#xff0c;是一种用于创建网页的标准标记语言。我们可以使用HTML建立自己的WEB网站或特定页面。HTML运行在浏览器上&#xff0c;由浏览器解析。 ⚠️注意&#xff1a;HTML文件的后缀…

STM32连接阿里云物联网平台

文章目录 引言一、STM32连接阿里云物联网平台思路二、ESP8266烧录固件三、使用AT指令连接阿里云物联网平台四、STM32环形串口缓冲区驱动程序五、STM32连接阿里云驱动程序 引言 连续写了两篇关于阿里云连接的文章&#xff0c;都是使用Arduino ESP8266 & Arduino ESP32的方式…

【虚拟机数据恢复】异常断电导致虚拟机无法启动的数据恢复案例

虚拟机数据恢复环境&#xff1a; 某品牌R710服务器MD3200存储&#xff0c;上层是ESXI虚拟机和虚拟机文件&#xff0c;虚拟机中存放有SQL Server数据库。 虚拟机故障&#xff1a; 机房非正常断电导致虚拟机无法启动。服务器管理员检查后发现虚拟机配置文件丢失&#xff0c;所幸…

【论文阅读】GraspNeRF: Multiview-based 6-DoF Grasp Detection

文章目录 GraspNeRF: Multiview-based 6-DoF Grasp Detection for Transparent and Specular Objects Using Generalizable NeRF针对痛点和贡献摘要和结论引言模型框架实验不足之处 GraspNeRF: Multiview-based 6-DoF Grasp Detection for Transparent and Specular Objects Us…

Vulnhub靶场DC-9

攻击机192.168.223.128 靶机192.168.223.138 主机发现 nmap -sP 192.168.223.0/24 端口扫描 nmap -sV -p- -A 192.168.223.138 开启了22 80端口 访问一下web页面 有个查询界面 测试发现存在post型的sql注入 用sqlmap跑一下&#xff0c;因为是post型的&#xff0c;这里…

C#使用RabbitMQ-1_Docker部署并在c#中实现简单模式消息代理

介绍 RabbitMQ是一个开源的消息队列系统&#xff0c;实现了高级消息队列协议&#xff08;AMQP&#xff09;。 &#x1f340;RabbitMQ起源于金融系统&#xff0c;现在广泛应用于各种分布式系统中。它的主要功能是在应用程序之间提供异步消息传递&#xff0c;实现系统间的解耦和…

RabbitMQ问题总结

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

Ubuntu20.4 Mono C# gtk 编程习练笔记(四)

连续实时绘图 图看上去不是很清晰&#xff0c;KAZAM录屏AVI尺寸80MB&#xff0c; 转换成gif后10MB, 按CSDN对GIF要求&#xff0c;把它剪裁缩小压缩成了上面的GIF&#xff0c;图像质量大不如原屏AVI&#xff0c;但应该能说明原意&#xff1a;随机数据随时间绘制在 gtk 的 drawin…

使用OpenCV实现一个简单的实时人脸跟踪

简介&#xff1a; 这个项目将通过使用OpenCV库来进行实时人脸跟踪。实时人脸跟踪是一项在实际应用中非常有用的技术&#xff0c;如视频通话、智能监控等。我们将使用OpenCV中的VideoCapture()函数来读取视频流&#xff0c;并使用之前加载的Haar特征级联分类器来进行人脸跟踪。 …

浅谈Python两大爬虫库——urllib库和requests库区别

目录 一、urllib库 1、使用方法 2、功能 3、效率 二、requests库 1、使用方法 2、功能 3、效率 三、总结与建议 在Python中&#xff0c;网络爬虫是一个重要的应用领域。为了实现网络爬虫&#xff0c;Python提供了许多库来发送HTTP请求和处理响应。其中&#xff0c;url…

MySql8的简单使用(1.模糊查询 2.group by 分组 having过滤 3.JSON字段的实践)

MySql8的简单使用&#xff08;1.模糊查询 2.group by 分组 having过滤 3.JSON字段的实践&#xff09; 一.like模糊查询、group by 分组 having 过滤 建表语句 create table student(id int PRIMARY KEY,name char(10),age int,sex char(5)); alter table student add height…