并查集——分数调查(模板+节点距离标记)

题意描述:
根据已知节点之间的分数关系(建树),算出题目要求的两个节点之间的分数差距;
主要需要解决的就是节点之间的距离记录,其他的部分套用模板即可(主要看代码中的描述即可)
解题思路:
在找根节点和合并子集(建树)的时候将该节点到根节点的距离记录下来,在最后判断如果两个节点根节点在一棵树上将其到根节点的距离相减就行(在初始化时也将其到根节点距离归0)
节点之间距离具体实现:
dis数组的实现
初始化时:dis[i]=0每节点都是自己的boss所以到根结点的距离为0;
找根节点:dis[v]=dis[v]+dis[t]到根节点的距离等于节点到父亲节点的距离 加上父亲节点到根节点的距离;
合并子集(建树):dis[t2]=d+dis[v]-dis[u];按照本来的方程应该是dis[u]+dis[t2]+(-dis[v])=d;
将其简化后就是当前的公式了;
题目:
小Hi的学校总共有N名学生,编号1-N。学校刚刚进行了一场全校的古诗文水平测验。
学校没有公布测验的成绩,所以小Hi只能得到一些小道消息,例如X号同学的分数比Y号同学的分数高S分。
小Hi想知道利用这些消息,能不能判断出某两位同学之间的分数高低?
Input
第一行包含三个整数N, M和Q。N表示学生总数,M表示小Hi知道消息的总数,Q表示小Hi想询问的数量。
以下M行每行三个整数,X, Y和S。表示X号同学的分数比Y号同学的分数高S分。
以下Q行每行两个整数,X和Y。表示小Hi想知道X号同学的分数比Y号同学的分数高几分。
对于50%的数据,1 <= N, M, Q <= 1000
对于100%的数据,1 <= N, M, Q<= 100000 1 <= X, Y <= N -1000 <= S <= 1000
数据保证没有矛盾。
Output
对于每个询问,如果不能判断出X比Y高几分输出-1。否则输出X比Y高的分数。
Sample Input

10 5 3  
1 2 10  
2 3 10  
4 5 -10  
5 6 -10  
2 5 10  
1 10  
1 5  
3 5

Sample Output

-1  
20  
0

AC代码:

#include<stdio.h>
int f[100005],dis[100005];//dis数组为与根节点的分数差
int n,m;	
void init()
{
	for(int i=1;i<=n;i++) 
	{
		f[i] = i;
		dis[i] = 0;//开始的时候自己就是自己的老板(即所谓的根节点所以距离为0)
	}
}
int getf(int v)
{
	if(f[v]==v)
	return v;
	int t=f[v];
	f[v]=getf(f[v]);       //dis[v]存储的是x与父亲节点的差
	dis[v]=dis[v]+dis[t]; //dis[t]存储父亲与根节点的差 
	return f[v];
}
void merge(int v,int u,int d)
{
	int t1,t2;
	t1=getf(v);
	t2=getf(u);
	if(t1!=t2)
	{
		f[t2]=t1;
		dis[t2]=d+dis[v]-dis[u];
	}
	return ;
}
int main()
{
	int x,y,d,i,q;
	while(scanf("%d %d %d",&n,&m,&q)!=EOF)
	{
		init();
	for(i=1;i<=m;i++) 
	{
		scanf("%d %d %d",&x,&y,&d);
		merge(x,y,d);
	}
	for(int i=1;i<=q;i++)
	{
		scanf("%d %d",&x,&y);
		if(getf(x)==getf(y))
			printf("%d\n",dis[y]-dis[x]);
			//在存储的时候记录的是后节点到前一节点之间的距离也就是说子节点-父节点=
			//题目所给的距离刚好与题目中描绘的前节点比后面节点大相反
		else
			printf("-1\n");
	   }
	}
	return 0; 
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮皮皮皮皮皮皮卡乒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值