题目解释:
给定n个数,m个数据对,数据对中有abc a代表起始数字,b代表终止数字,c代表权值,可以理解为a到b的距离我们要在给出的m个数据对中,找出自相矛盾的数据对,统计一共有多少对错误。
举例说明
为了方便后边,我们把右边的闭区间改为开[a,b+1)
n=10,m=5(数字1~10,5个数据对)
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1
[1,11)距离为100
[7,11)距离为28
[1,4)距离为32
[4,7)距离为41
[6,7)距离为1
输出 1
解题思路:
对于这个题目,我们是不知道数列的具体内容,只知道若干区间上的距离是多少,然而如果区间是相邻的,那么他们可以组成一个更大的区间,也就是通过已有区间能推理出更多区间和。
这道题使用带权并查集的做法很好处理,每一个节点表示一个区间的起点,它的父亲节点表示这个左闭右开区间的右端点,边上的权值就存放起点到父亲节点的距离,对于给出每一组数据对,判断是否连通,如果是,就判断给出的数据和推得的数据是否吻合,如果不连通,就通过并查集的合并操作使其连通!
图示:
此图解释了4 6 41 的错误进行解释,大家好好理解!
findFa()进行解释:
int findFa(int x)
{
if(x==fa[x])return x;
int new_fa=findFa(fa[x]);//用new-fa暂存父亲节点
value[x]+=value[fa[x]];//更新x的value值
fa[x]=new_fa;//路径压缩
return fa[x];
}
这个find方法和普通的并查集find方法唯一区别在于,要更新value值,并且要压缩路径!我用一个图片来解释,执行findFa()后的效果,至于执行细节、大家用一组数据写写画画即可!
代码:(有详细解释)
#include<bits/stdc++.h>
#define maxn 200010
using namespace std;
int fa[maxn],value[maxn];//fa存放父亲节点,value存放到父亲节点的距离
int n,m,ans;
int findFa(int x)
{
if(x==fa[x])return x;
int new_fa=findFa(fa[x]);//用new-fa暂存父亲节点
value[x]+=value[fa[x]];//更新x的value值
fa[x]=new_fa;//路径压缩
return fa[x];
}
int main()
{
while(cin>>n>>m)
{
//并查集初始化
for(int i=1; i<=n; i++)
{
fa[i]=i,value[i]=0;//初始权值0
}
int a,b,s;
for(int i=1; i<=m; i++)
{
cin>>a>>b>>s;
if(findFa(a)==findFa(++b))//a和b+1有相同父亲节点
{
ans+=value[a]!=(value[b]+s);//如果相等返回0,不相等ans++
}
else
{
//不连通情况,进行Union合并
value[fa[a]]=s+value[b]-value[a];//先更新a的父亲节点的权值
fa[fa[a]]=fa[b];//将a的父亲节点,连接到b的父亲节点
}
}
printf("%d",ans);
}
return 0;
}
对这段代码进行图解:
value[fa[a]]=s+value[b]-value[a];//先更新a的父亲节点的权值
fa[fa[a]]=fa[b];//将a的父亲节点,连接到b的父亲节点
这是a,b不连通情况,我们要变为连通。(a,b父亲为c,d并都用大写)
这道题就讲到这里了,作图不易,大家点个赞,粉丝太少了呜呜~~多多关注!