首页 > 其他分享 >(测试)带权并查集

(测试)带权并查集

时间:2023-09-04 19:33:04浏览次数:44  
标签:dsu int 查集 带权 测试 权值 节点

带权并查集

普通的并查集只能维护每个节点所在集合的编号,带权并查集则可以维护集合内任意一点到所在集合根的距离。

带权并查集结点存有权值信息的并查集。相比于一般的并查集,带权并查集需要开辟两个数组:一个是dsu[N],用来判断集合关系;一个是dis[N],用来描述其与根节点的关系。

当两个元素之间的关系可以量化,并且关系可以合并时,可以使用带权并查集来维护元素之间的关系。

带权并查集每个元素的权值通常描述其与并查集中祖先的关系,这种关系如何合并,路径压缩时就如何压缩。

带权并查集可以推算集合内点的关系,而一般并查集只能判断属于某个集合。

结论(带权并查集做题流程):

首先看有没有类似并查集的用法,能不能通过集合的方式做题;接着看需不需要额外维护权值,如果要就要看两个东西:

  • 合并的时候,权值如何运算。

    • 并查集的统一合并操作:合并a->b,就要找到a和b的父节点,然后在两个父节点之间连边,运算出来的结果就是这条边的权值。
  • 查询的时候,如何得到所查节点的权值。

    • 知道两个节点到根节点的权值,如何得到两个节点之间的权值。

以下例题1是解释什么是带权并查集的。

例题1:

有一个长度为 N 的整数序列。

下面会按顺序给出 M 个对该序列的描述,每个描述给定三个整数 l,r,s,表示该序列的第 l 个元素至第 r 个元素相加之和为 s。

对于每个描述,你需要判断该描述是否会与前面提到的描述发生冲突,如果发生冲突,则认为该描述是错误的。

如果一个描述是错误的,则在对后续描述进行判断时,应当将其忽略。

请你计算一共有多少个描述是错误的。

输入格式

第一行包含两个整数 N,M。

接下来 M 行,每行包含三个整数 l,r,s,表示一个描述。

输出格式

一个整数,表示错误描述的数量。


带权并查集的解释:

dis[]表示某个节点到根节点的权值

在这题的含义就是某个端点(节点)到另一个端点(根节点)所构成的区间的和,这里不需要管这两个点谁小谁大,因为权值可以是负数,最后计算的结果是没有影响的。

  • 由这个dis数组,可以得到在同一个集合内,所有节点之间的权值

初始化的时候,dis[]全为0,表示自己到自己的权值为0。


如何理解权值的合并:

image-20230320173815909

合并两个集合的操作,可以通过向量的方法来理解:dis数组用于记录节点到根节点的距离,然后每种关系如图所示,最终我们需要将fx接到fy上去,所以我们需要修改fx的权值,也就是向量fx->fy,如下图所示的向量计算。

Screenshot_20230320_174553_com.newskyer.draw image-20230320173855239

注意刚刚说的,dis所表示的权值可能是负数,如果用向量去理解,就很好理解:如下图所示,区间中蓝色和绿色的区间是已知的,然后现在需要添加 $(l_2,r]$ 或者说:($l_2$->r),已经合并好的集合如下面所示,找到$l_2$的父节点$r_2$,r的父节点$r_1$,需要添加一条边$r_2$->$r_1$ 这时候就会发现,假如从左到右的箭头表示权值为正数,那么新加入的边权值居然变成了负数,但是最后是不影响计算的结果的(后面有解释)。

Screenshot_20230520_203228_com.newskyer.draw

如果是询问节点间的权值是否为v,那么由于两个节点都在集合内,所以有共同的根节点,所以只要计算 $(l,rot) -(r,rot)$ 是不是等于v即可(向量的意思)

对前面负数权值的解释:比如,询问$r_1$->$r_2$ ,计算$(r_1,rot) 减(r_2,rot)$ ,$(r_1,rot)$中$r_1$就是根节点,所以是0; $(r_2,rot)$ 中rot是$r_1$ ,权值我们是知道的,就是$dis[r_2]$ ,所以最后的结果就是$0-dis[r_2]$ ,最后结果又变成了正数。

AcWing 4286. 多少个答案是错误的 - AcWing <-举例

注意!!!

针对本题,根据区间合并原理,我们将左端点-1处理成左开右闭区间,(0,3] + (3, 10] = (0,10] == [1,10].

因为,如果存的是闭区间[1,5]和[5,10]合并,5下标的数就会被算了两次,处理之后才可以直接通过三个点得到两个区间的关系--(0,5]应该和(5,10]区间合并,而不是[5,10],[5,10]会被处理成(4,10],也就是说前面说的两个区间是有重叠的。

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

#define int long long
vector<int> dsu(200005);
vector<int> d(200005);//存权值,表示到根
int ans = 0;

int find(int x) {
    if (x != dsu[x]) {
        int rot = dsu[x];//记录父节点编号
        dsu[x] = find(dsu[x]);
        d[x] += d[rot];//从根节点开始回溯,把权值累加
    }
    return dsu[x];
}

void root(int x, int y, int v) {
    int x_ = find(x);//正常的并查集操作
    int y_ = find(y);
    if (x_ == y_) {
        ans += (d[x] - d[y] != v);
    } else {
        dsu[x_] = y_;//将x的根节点接到y的根节点上去
        d[x_] = v + d[y] - d[x];//修改权值
    }
}

signed main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        dsu[i] = i;//初始化并查集
        d[i] = 0;//初始化权值
    }
    for (int i = 1; i <= m; i++) {
        int x, y, v;
        cin >> x >> y >> v;
       x--;//记得减一,处理为左开右闭区间
        root(x, y, v);
    }
    cout << ans << endl;
}

240. 食物链 - AcWing题库

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

vector<int> dsu(500005);
vector<int> d(500005);
int ans ;
int find(int x) {
    if (x != dsu[x]) {
        int rot = dsu[x];
        dsu[x] = find(dsu[x]);
        d[x] = (d[rot] + d[x]) % 3;
    }
    return dsu[x];
}


void root(int x, int y, int v) {
    int x_ = find(x);
    int y_ = find(y);
    if (x_ == y_) {
       if(v != (d[x] - d[y] + 3) % 3){
            ans++;
       // cout << x << ' ' << y << ' ' << v << "?" << (d[x] - d[y] + 3) % 3 << endl;
       }
    } else {
        dsu[x_] = y_;
        d[x_] = (v + d[y] - d[x]) % 3;
    }
}

int main() {
    int n, t;
    cin >> n >> t;
    for (int i = 1; i <= n; i++) {
        dsu[i] = i;
    }
    for (int i = 1; i <= t; i++) {
        int tmp, x, y;
        cin >> tmp >> x >> y;
        if (tmp == 2 && x == y)
            ans++;
        else if (x > n || y > n)
            ans++;
        else {
            root(x, y, tmp - 1);
        }
       
    }
     cout << ans << endl;
}

AcWing 240. 食物链(带权并查集) - AcWing

标签:dsu,int,查集,带权,测试,权值,节点
From: https://www.cnblogs.com/kaiweikfuse/p/17677918.html

相关文章

  • [kuangbin带你飞]专题五 并查集
    WirelessNetwork POJ-2236 题意:n台电脑,坐标(x,y),电脑通讯范围为d;一开始,给出所有电脑坐标,然后所有电脑初始状态都是坏的,题目输入两个操作,第一修电脑且这台电脑可对d范围内正常电脑进行通讯了;第二就是查询,两台电脑是否可以通讯?算法:并查集思路:第一次,我直接通过坐标判断,那些电......
  • 1141 PAT Ranking of Institutions(附测试点5分析)
    题目:AftereachPAT,thePATCenterwillannouncetherankingofinstitutionsbasedontheirstudents'performances.Nowyouareaskedtogeneratetheranklist.InputSpecification:Eachinputfilecontainsonetestcase.Foreachcase,thefirstline......
  • Linux MeterSphere一站式开源持续测试平台远程访问
    @[TOC]前言MeterSphere是一站式开源持续测试平台,涵盖测试跟踪、接口测试、UI测试和性能测试等功能,全面兼容JMeter、Selenium等主流开源标准,有效助力开发和测试团队充分利用云弹性进行高度可扩展的自动化测试,加速高质量的软件交付,推动中国测试行业整体效率的提升。下面介绍在L......
  • 智能座舱HMI自动化测试之语音交互专项测试
    随着人工智能和物联网技术的迅猛发展,智能座舱已经成为现代汽车中的重要组成部分。语音交互作为智能座舱的核心功能之一,正日益受到用户和汽车制造商的关注。车载语音交互具备的独特优势:降低驾驶者对车内设备的操作依赖、增加驾驶安全系数,完善车载语音的用户体验,保证语音的准确......
  • [ 总结 ] Linux系统测试硬盘I/O
    检测硬盘I/O相对来说还是一个比较抽象的概念,但是对系统性能的影响还是至关重要的。(1)使用hdparm命令检测读取速度:   hdparm命令提供了一个命令行的接口用于读取和设置IDE和SCSI硬盘参数。   安装:      yuminstallhdparm   语法:      hdparm(选项......
  • 软件测试—性能测试的专业术语1
    以下都是性能测试中出现频率比较高的词汇。掌握了这些基础的性能测试知识、可以更好地开展测试工作。典型的术语主要有并发用户、并发用户数量、请求响应时间、事物响应时间、吞吐量、TPS、点击率、资源利用率等。并发用户: 并发一般分两种情况。一种是严格意义上的并发,即所有的用......
  • 软件测试 | Dalvik虚拟机是如何执行程序的
    Android系统的架构采用分层思想,这样的好处是拥有减少各层之间的依赖性、便于独立分发、容易收敛问题和错误等优点。Android系统由Linux内核、函数库、Android运行时、应用程序框架以及应用程序组成。如图3-4的Android系统架构所示,Dalvik虚拟机属于Android运行时环境,它与一些核心库......
  • 软件测试 | Selenium-Grid架构
    Selenium-Grid是基于传统Selenium架构发展起来的,它有如下优点:1.Selenium测试案例、待测Web应用系统、RemoteControl/浏览器组合之间无须紧密耦合。它们之间通过HTTP进行通信,因此不需要工作在一台机器上。2.Selenium测试案例和待测Web应用系统与具体项目相关。不过,无论SeleniumRem......
  • 软件测试 | Selenium-RC工作原理
    我们描述Selenium-RC组件是如何运转的,以及它们在测试案例运行过程中扮演什么角色。1.RC组件Selenium-RC组件包括:SeleniumServer,它负责启动和关闭浏览器,解释和运行从测试程序传来的Selenium命令,就像一个HTTP代理一样。截取和验证浏览器与待测应用(AUT)之间的HTTP消息;客户端库文件提供......
  • 软件测试 | Selenium基础
    Selenium命令——SeleneseSelenium提供一系列命令,可以用你能想到的所有方式全面测试你的Web应用系列。这些命令通常被称为Selenese。这些测试命令事实上构成了一种测试语言。使用Selenese,用户可以通过HTMLtags测试UI元素是否存在,测试特殊文本,测试死链接、输入框、下拉列表、提交表......