hdu 3038 How Many Answers Are Wrong (带权并查集入门)

来源:互联网 发布:京东和淘宝联盟类似 编辑:程序博客网 时间:2024/06/06 09:13

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

How Many Answers Are Wrong

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


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
 

带权并查集,第一次接触,算上读题,用了半天的时间才A掉,而且是在参照多个题解的情况下........

题意:给你一个区间和区间每个元素之和,问有多少组数据是不符逻辑的

题解:细节太多了,光靠题解往回推做法都推了半天,正着想的人脑子不知什么做的.......

要点

①:任何区间只要不是完全重合就符合逻辑,就算是,若他们的值是一样的也符合逻辑

eg: 样例里 区间[1, 10] 和 [1, 3] [4, 6] [7, 10]三个区间和完全重合了,并且值不一样,所以肯定不符逻辑

那么有多少组不符逻辑呢?就是:哪组数据的加入使现有的组合不合逻辑,就有几组

如样例中最后[1, 10]的加入使[1, 3] [4, 6] [7, 10]这个组合不合逻辑,所以只有一组

这里刚开始会思考如果我们的组合一开始是[1, 10],后来加入[1, 3] [4, 6] [7, 10],会不会是3组不合逻辑呢

答案是不会,因为[1, 10]与[1, 3] [4, 6]在一起也符合逻辑,即还没完全重合之前怎么变次序都符合逻辑

这样会让最终答案并不受次序的更变而变化

②:由①可以启发到(反正我就启发不到......)把区间集合起来,不能加入的区间就是不符逻辑的,从而可以想到并查集

怎么并??这是最最难的......首先,我们要搞个带权的并查集,这个权是什么呢?在这里是距离,到老大的距离,

用dis[]存放,则每个点i都有一个到老大的距离dis[i], 那么这玩意怎么更新呢?这和这个并查集的设计有关,

要灵活变通

③:关键一点,怎么并?怎么设计并的内容与方法(这里也要灵活变通,不能瞎抄)?我的想法是让区间的起点做大佬,

数值小的做大佬(大的也可以),然后获取每段区间时,先检查一下他们的大佬,如果他们的大佬相同,则这段区间

已经在记录中,这时要检查一下这区级的两端点到大佬的距离(这就是为什么小的做大佬的原因,方便距离的比较

因为大佬肯定比这两个点小,所以这两个点的相对距离很好确认,只要dis相减即可,如果不强行设计为小的做大佬,

而是任意点都可以,就会产生距离的计算复杂的问题,试想这两个点一个可能在大佬的左边,一个在右边或者两个

都比大佬小等等)。如果这两个点的大佬不等,不在同一个集合中,那么就并吧,怎么并?这里要分一个类,两个

端点的大佬究竟谁大一点?根据我们并的原则,小的优先,把小的做大的大佬,然后只要更改被合并的大佬到新大佬

的距离即可,这个距离在两种情况下是不同的,具体可以画连个集合,手动连线并起来看看(这里WA了好多次)

如集合:        x                           y
                      ②                          ⑤
                   ↓    ↓                    ↓    ↓  
                 ④     ⑥  --------   ⑧     ⑨
                          u                   v
dis[y] = w - dis[v] + dis[u];

这里还要讨论y与u哪个大的情况,但是会发现无论y和u哪个大,式子都一样


          x                           y
        ③                          ②
      ↓    ↓                      ↓    ↓  
    ④     ⑥  --------    ⑧     ⑨
            u                   v

然这是第二种情况:dis[x] = dis[v] - w - dis[u]; 

④:最后,还要个问题,就是为什么查并集压缩路径中可以直接:dis[x] += dis[fa[x]];

原因在于每次的更新都把所有的子节点直接指向父亲了,下一次再查的时候由于父亲到自己的距离为0,

所以可以放心地加上0来保持不变,而当父亲更新时(即父亲找到老爷子),直接加上父亲到老爷子的距离即可更新

为自己到老爷子的距离

#include<iostream>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<stack>#include<queue>#include<vector>#include<map>#include<set>using namespace std;#define ll long longconst int maxn = 200000 + 10;int fa[maxn];int dis[maxn];      //to rootint findx(int x){     if (fa[x] == -1)          return x;     int tmp = findx(fa[x]);//不能直接写成:   fa[x] = findx(fa[x]); dis[x] += dis[fa[x]];     dis[x] += dis[fa[x]];//这样就改了原来父节点,不能获得原来正确的值     return fa[x] = tmp;}void init(){     memset(dis, 0, sizeof(dis));     memset(fa, -1, sizeof(fa));     return;}int uni(int u, int v, int x, int y, int w){     if (x < y)//画图看合并的情况     {          fa[y] = x;          dis[y] = w - dis[v] + dis[u];     }     else     {          fa[x] = y;          dis[x] = dis[v] - w - dis[u];     }     return 0;}int main(){     int n, m;     while (~scanf("%d%d", &n, &m))     {          init();          int i, j;          int x, y;          int u, v, w;          int ans = 0;          for (i = 0; i < m; i++)          {               scanf("%d%d%d", &u, &v, &w);               u--;               x = findx(u);               y = findx(v);               if (x == y && dis[v] - dis[u] != w)                    ans++;               else if (x != y)                    uni(u, v, x, y, w);          }          printf("%d\n", ans);     }     return 0;}


0 0
原创粉丝点击