How Many Answers Are Wrong并查集

How Many Answers Are Wrong
原题链接https://vjudge.net/contest/350427#problem/D
在这里插入图片描述
在这里插入图片描述
本题为带权并查集 ,给你两个点之间的距离,然后推出下一条是否正确,
题目的.重点在于如何对并查集进行合并,关于权值的计算。
本题计算时我使用的方法可以理解为坐标轴的计算,
全部合并到较小的数上去,也就是以最小的值为根
对于样例而言
先将1跟10链接
在这里插入图片描述
通过权值的关系我们可以计算出每个点到达0点的关系(将所有区间的左区间减一位变为开区间),
0~3:32
0~6:100-28=72;
0~10:100;
在我们得到4~6之后,显然3-6这个区间两边的端点都有根,并且根相同,权值便可以直接计算,为6的权值减去3的权值,然后和题目给出的值进行计算,判断是否相同

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<fstream>
#include<queue>
using namespace std;
long long pre[300005];
long long rank1[300005];
long long find(long long x)
{
	if(x==pre[x])
	{
		return x;
	}
	long long t=pre[x];
	pre[x]=find(pre[x]);
	rank1[x]+=rank1[t];
	return pre[x];
}
void join(long long x,long long y,long long a,long long b,long long c)
{
	if(x>y)//对于根的不同大小进行合并,具体有公式就根据坐标轴推出即可
	{
		pre[y]=x;
		rank1[y]=rank1[a]-rank1[b]-c;
	}
	else
	{
		pre[x]=y;
		rank1[x]=rank1[b]-rank1[a]+c;
	}
}
int main()
{
	long long n,m;
	while(~scanf("%lld %lld",&n,&m))
	{
		long long i,j;
		memset(rank1,0,sizeof(rank1));
		for(i=0; i<=200001; i++)
		{
			pre[i]=i;
		}
		long long sum1,sum2,sum3;
		long long sum=0;
		while(m--)
		{
			scanf("%lld %lld %lld",&sum1,&sum2,&sum3);
			sum1--;
			long long ss1=find(sum1);
			long long ss2=find(sum2);
			if(ss1==ss2&&rank1[sum1]!=rank1[sum2]+sum3)//根相同说明已经连接起来,可以判断,进行判断
			{
					sum++;
			}
			else if(ss1!=ss2)
			{
				join(ss1,ss2,sum1,sum2,sum3);//两个不同的集合进行合并。
			}
		}
		printf("%lld\n",sum);
	}
	return 0;
}

发布了135 篇原创文章 · 获赞 3 · 访问量 1918

猜你喜欢

转载自blog.csdn.net/yeyuluo/article/details/103974414