HDU-3038 How Many Answers Are Wrong [带权并查集]代码+讲解

How Many Answers Are Wrong

TT and FF are … friends. Uh… very very good friends -________-b

FF is a bad boy, he is always wooing TT to play the following game with him. This is a very humdrum game. To begin with, TT should write down a sequence of integers-_-!!(bored).

Then, FF can choose a continuous subsequence from it(for example the subsequence from the third to the fifth integer inclusively). After that, FF will ask TT what the sum of the subsequence he chose is. The next, TT will answer FF’s question. Then, FF can redo this process. In the end, FF must work out the entire sequence of integers.

BoringBoringa very very boring game!!! TT doesn’t want to play with FF at all. To punish FF, she often tells FF the wrong answers on purpose.

The bad boy is not a fool man. FF detects some answers are incompatible. Of course, these contradictions make it difficult to calculate the sequence.

However, TT is a nice and lovely girl. She doesn’t have the heart to be hard on FF. To save time, she guarantees that the answers are all right if there is no logical mistakes indeed.

What’s more, if FF finds an answer to be wrong, he will ignore it when judging next answers.

But there will be so many questions that poor FF can’t make sure whether the current answer is right or wrong in a moment. So he decides to write a program to help him with this matter. The program will receive a series of questions from FF together with the answers FF has received from TT. The aim of this program is to find how many answers are wrong. Only by ignoring the wrong answers can FF work out the entire sequence of integers. Poor FF has no time to do this job. And now he is asking for your help~(Why asking trouble for himself~~Bad boy)

Input

Line 1: Two integers, N and M (1 <= N <= 200000, 1 <= M <= 40000). Means TT wrote N integers and FF asked her M questions.

Line 2…M+1: Line i+1 contains three integer: Ai, Bi and Si. Means TT answered FF that the sum from Ai to Bi is Si. It’s guaranteed that 0 < Ai <= Bi <= N.

You can assume that any sum of subsequence is fit in 32-bit integer.

Output

A single line with a integer denotes how many answers are wrong.

Sample Input

10 5
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1

Sample Output

1

题意大概:有一串整数数列,共有 n 个数。现在有 m 次查询,ai , bi , si 代表从第 ai 个整数到第 bi 个整数的和为 si 。问根据这些查询一共有多少个错误查询。
这道题很容易想到很难,其实只用每次将当次查询前的查询当做正确的。以此为基础进行判断,如果和前面的冲突,那么错误的个数就加一,再把它无视掉。如果不冲突,就用这次查询维护现有的关系。

算法方面可以用带权并查集实现,这也是第一次写带权并查集。。
思路参考传送门——

每个实数都有自己的值可以看做带权的边,这些实数线性排列就是一个首尾相连的边组成的图。在数组的头尾和每两个实数间都有一个节点;用rank数组保存到根的距离(在压缩路径后)(有点像前缀和???)剩下的在代码注释里都说的挺清楚了
注意:有多组数据!!!

#include<cstdio>
#define pointnumber 200005
using namespace std;
long long int rank[pointnumber],fa[pointnumber],n;
//fa[]保存下标对应的点的父节点是谁
//rank[]保存下标对应点到父节点的距离 ,n是节点的数量 
void init()//初始化 
{
	for(long long int i=1;i<=n+1;i++)//有n个数字,把每个数字当做一条首尾相连的边 
	{//那么就有n+1个节点,例如第一个数字在节点1,2之间 
		fa[i]=i;//将所有点的父节点都设为它本身
		//当然也可任意选一个不会发生误会的数 例如-1,-2.... 
		
		rank[i]=0;//rank[]保存这个点到父节点的距离
		//刚开始还没有合并,所以每个点都是根节点
		//所以距离就是0
	}	
}
long long int find(long long int a)//找到根节点并压缩路径 
{
	if(fa[a]==a)//根据初始化的条件找到了根节点 
	{
		//find()函数是返回根节点,维护并压缩路径的函数 
		return a; //而根节点根本不需要维护,只要直接返回它的编号就好 
	}
	long long int temp=find(fa[a]);//递归,继续寻找父节点的父节点
	//最后会返回根节点,所以也是路径压缩 
	//这里不能直接对fa[a]赋值,因为现在rank[a]还保存着和父节点的距离
	//如果覆盖掉fa[a],就不知道当前节点和根节点的距离
	//和根节点距离还是要靠父节点中转,来计算 。所以还是要知道父节点是谁; 
	
	rank[a]+=rank[fa[a]];//这里是在递归调用之后,所以父节点的路径已经被压缩好了
	//并且父节点rank[]的值也保存为父节点到根节点的值
	//rank[]永远保存的是与父节点的距离
	//只是在压缩路径后所有的点除了根节点。。。(好像也包括根。。。)(逃。。) 
	//所有访问过的的点,其父节点都是根节点 
	//当前点到父节点距离加上父节点到根节点距离就是当前点到根节点距离 
	
	fa[a]=temp;//现在rank[]已近更新完了,保存的也是当前点到根节点距离
	//所以也要把当前点的父节点设为根节点
	
	return fa[a];//就这样当前点就维护完了,为上一层递归返回根节点编号 
}
int main()
{
	long long int i,j,m,ai,bi,si,fx,fy,ans;
	
	while(scanf("%lld%lld",&n,&m)!=EOF)//n是节点的数量,作为全局变量可以在初始化时用上
	{	//m是询问和回答的次数
		init();ans=0;
		for(i=1;i<=m;i++)
		{
			scanf("%lld%lld%lld",&ai,&bi,&si);//ai,bi,si代表起点,终点,其间数字的和; 
			//数据保证ai<=bi; 
			bi++;//ai数值对应的节点在第ai个数字之前
			//而bi对应的节点在第bi个数字之前,第bi个数字后面的节点是bi+1
			//所以要完整的表示这个区间的数字bi要加一
			
			fx=find(ai);
			fy=find(bi);//将ai,bi的根节点找到
			
			if(fx!=fy)//如果不在一棵树上
			{
				fa[fy]=fx;//我们这里将编号较小的节点作为父节点,反过来也是可以的(大概。。) 
				rank[fy]=rank[ai]+si-rank[bi];
				//这里有四个点fx,fy,ai,bi
				//现在要将fy代表的树并入以fx为根的树
				//rank[fy]就要变为fy到父节点也就是根节点fx的距离
				//rank[ai],rank[bi]分别代表ai,bi到fx,fy的距离(调用find()函数时已经压缩过路径了)
				//这四个点都是线性排列只到其中三条边的距离,就可以算出rank[fy]
				//可以在纸上画一下 
			} 
			else//如果在同一棵树上
			{
				if(si!=rank[bi]-rank[ai])
				ans++;//说明出现了矛盾 错误数量+1 
			} 
			 
		} 
		printf("%lld\n",ans); //最后输出答案 
	}	
	return 0;
} 
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值