HDU 3038 How Many Answers Are Wrong 扩展并查集

http://acm.hdu.edu.cn/showproblem.php?pid=3038

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.

Boring~~Boring~~a 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条线段,告诉你m条线段点的权值之和。(理解这点很重要,理解成线段的话就大错特错了)比如样例中1 10 100就是说从1到10的10个点的权值之和是100。让你判断其中逻辑错误的有几个。(当当前输入和以前的没有冲突 就可以认为是正确的 否则就是错误的)

思路:扩展并查集,已经写过两篇这种题目了。感觉就是自己设置偏移量(有方向的),然后就可以按照向量的加减法来推导关系了。可以看看这位博主的:

https://www.cnblogs.com/liyinggang/p/5327055.html

令附上另外两道题的题解:

https://mp.csdn.net/postedit/86650735

https://mp.csdn.net/postedit/86653185

我先来扯一下为什么要按照点有权值而不是线段有权值来理解。(我一开始也认为给的是线段的值,然后看题解、看思路总感觉怪怪的)我给大家先举两个例子,假设n=4,m=3,第一次我们分别输入 1 4 4;2 4 3;1 2 2;这时候你按照区间权值来理解,很明显是有问题的。因为[1,4]=4;[2,4]=3;那么[1,2]很显然是11 2 2是矛盾的输入,程序应该输出1啊,但是程序输出的是0,不信你可以随便找个AC代码试一下,说明这种理解方式是错误的。然后我们试试以点有权值的方式来理解。[1,4]=4 说明1、2、3、4四个点的权值之和是4,[2,4]=3,说明2、3、4三个点的权值之和是3,而[1,2]指的是1、2两个点的权值之和,因此我们从前两个条件推不出来第三个条件是矛盾的,(这就是为什么程序会输出0)但是我们能推出来点1的权值就是1,那我们来验证一下,把最后输入的分别改为 1 1 2(点1的权值是2)和 1 1 1(点1的权值是1)得到的答案分别是1和0,这说明按照点具有权值来理解是没有问题的。(可以自己验证别的数据 )

这道题呢,我们利用一个sum数组,sum[i]存储从结点i到其根结点的所有结点权值之和。初始化的时候,可以把sum初始化为0,下面来推导关系,首先就是在Find函数的路径压缩的时候,怎么修改sum数组的值。

这种情况必然是B、C先连接,然后再跟A连接后查询C父节点时候的情况。那么sum[C]存储到是C到B的,sum[B]存储的是B到A的,那么C到A自然是sum[C]+sum[B],也符合向量的加法:C->A=C->B+B->A;再看合并操作:

根据向量的运算法则,我们有:A->B=A->C+C->D+D->B

也即sum[A]=-sum[C]+d+sum[D]

判断是否有矛盾的情况:(矛盾情况必然发生在两个点的根结点相同,但两者之间的距离出现了矛盾)

若此时读入A与B的距离d,那么如果没有矛盾的话,应该满足:A-B=A->C+C->B

sum[A]-sum[B]=d 若不满足,则说明当前输入是错误的,跳过就可以了。

这道题还要注意一下,区间取的是左闭右闭的,所以处理的时候左边界要减1。

#include<iostream>
#include<cstdio>
#include<stack>
#include<cmath>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<iterator>
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

int f[200005];
int sum[200005];
int n,m;

void init()
{
	for(int i=0;i<=n;i++)
	{
		f[i]=i;
		sum[i]=0;
	}
}

int Find(int x)
{
	if(f[x]==x)
		return x;
	int temp=f[x];
	f[x]=Find(f[x]);
	sum[x]=sum[x]+sum[temp];
	return f[x];
}

int Union(int x,int y,int d)
{
	int fx=Find(x),fy=Find(y);
	if(fx!=fy)
	{
		f[fx]=fy;
		sum[fx]=d-sum[x]+sum[y];
		return 1;
	}
	else
	{
		if(d!=sum[x]-sum[y])
			return 0;
	}
	return 1;
}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		init();
		int x,y,d;
		int cnt=0;
		for(int i=0;i<m;i++)
		{
			scanf("%d %d %d",&x,&y,&d);
			x--;
			if(!Union(x,y,d))
				cnt++;
		}
		printf("%d\n",cnt);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xiji333/article/details/86665244