hdu 3084 How Many Answers Are Wrong【带权并查集】

来源:互联网 发布:蓝点网络 编辑:程序博客网 时间:2024/04/28 12:37

How Many Answers Are Wrong

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4404    Accepted Submission(s): 1683


Problem Description
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 51 10 1007 10 281 3 324 6 416 6 1
 

Sample Output
1
 

题目大意:给出N个数,m个提问,其中m个提问表示【a,b】的和为s,问有多少个语句是错误的。

首先呢,这里我们规定,【当然你也可以反着规定。】,sum【a】是a到a祖先的距离。我令b的祖先连接到a--的祖先上。为什么是连接到a--的祖先上而不是a的祖先上呢?我们先讨论一个问题:什么时候算是一个不合法的语句。这里我们知道,sum【a】是a到其祖先的距离。【权值==距离==和】。sum【b】是b到其祖先的距离。如果a,b的祖先相同(也就是说a,b在一个并查集和中),那么如果s==sum【b】-sum【a】那么说明这是一个合法的语句,如果s!=s==sum【b】-sum【a】,那么这就说明这个语句是不合法的。

这个时候我们回头讨论为什么是a--。现在输入样例如下:

10 5

1 1 1

2 2 2

3 3 3

4 4 4

5 5 5

我们明显看的出,这五个语句没有任何不合法的地方,但是如果我们现在找一下a,b的祖先,发现都是其自己,那么说明,ab是一个并查集里边的元素,那么s==sum【b】-sum【a】才能合法,那么输出的值是5,显然不对,因为我们要得到的答案是0.

所以这个时候,我们要对a--,这个时候就判断a,b是两个集合中的元素,我们进行的操作也不是判断s和sum【b】-sum【a】的关系,而是连接两个点。这个时候,我们才能妥善处理这个问题。

刚刚说明了if(pa==pb)的时候要如何处理,那么我们现在就要处理if(pa!=pb)时候的处理方案了。我这里令b的祖先连接到a--的祖先上。

suma表示a--到其祖先的距离。

sumb表示b到其祖先的距离。

s表示b到a的距离。

sump表示pb到pa的距离。

这里suma,sumb是已知的。s也是已知的,这个时候我们要做的事情是连接两个集合,首先:f[pb]=pa;

然后再确定pb到pa的距离。

这里我们给出假设值,方便大家理解:

a----------------------------------------->pa       

3----------------------------------------->1         suma=24.

b----------------------------------------->pb

10---------------------------------------->5       sumb=30.

b----------------------------------------->a

10--------------------------------------->3        s=60;

要求sump,就是要求5----------->1的距离。

我们已知1-3是24.5-10是30,3-10是60,求5-1的距离,就是24+30-30=sump,也就是suma+s-sumb得到结果.

根据以上结论,我们给出核心代码的对应:


        for(int i=0;i<m;i++)        {            int a,b,s;            cin>>a>>b>>s;            a--;            int pa=find(a);            int pb=find(b);            if(pa!=pb)//如果祖先不一样            {                f[pb]=pa;//连接起来                sum[pb]=s+sum[a]-sum[b];并且算出sump的距离。            }            else            {                if(sum[b]-sum[a]!=s)output++;//如果是不合法的语句,计数器++;            }        }
然后是完整的AC代码:

注意路径压缩部分:

#include<iostream>#include<string.h>using namespace std;int f[200005];int sum[200005];int find(int x){    if(x!=f[x])    {        int pre=f[x];//pre是x的一个父节点。        f[x]=find(f[x]);//递归找祖先。        sum[x]+=sum[pre];//路径压缩部分。    }    return f[x];}int main(){    int n,m;    while(cin>>n>>m)    {        memset(sum,0,sizeof(sum));        for(int i=0;i<=n;i++)        {            f[i]=i;        }        int output=0;        for(int i=0;i<m;i++)        {            int a,b,s;            cin>>a>>b>>s;            a--;//强调问题是6 6 1这样的情况,无脑给算作不对。            int pa=find(a);            int pb=find(b);            if(pa!=pb)            {                f[pb]=pa;                sum[pb]=s+sum[a]-sum[b];            }            else            {                if(sum[b]-sum[a]!=s)output++;            }        }        cout<<output<<endl;    }}





















0 0
原创粉丝点击