HDU 3038(并查集续带权并查集)

上一篇博客,写了对并查集的基本了解和应用,主要是还是从数组的角度去理解并查集,应用也局限于并查集的基础操作,对于大批数据的合并查询功能,这篇博客写了点自己对并查集树角度的理解,和一些稍微复杂的应用。How Many Answers Are WrongTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K
摘要由CSDN通过智能技术生成

上一篇博客,写了对并查集的基本了解和应用,主要是还是从数组的角度去理解并查集,应用也局限于并查集的基础操作,对于大批数据的合并查询功能,这篇博客写了点自己对并查集树角度的理解,和一些稍微复杂的应用。

How Many Answers Are Wrong

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



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 5 1 10 100 7 10 28 1 3 32 4 6 41 6 6 1
 

Sample Output
  
  
1

题意:

根据所给区间的值,进行记录,如果询问区间差值可以由前面的记录计算出来,则进行判断是否出错,最后输出错误答案个数。

题解:

乍一看貌似和并查集没什么关系的题目,我们只需在传统并查集的基础上增加一个sum[]数组表示到根节点的距离,对于询问的区间,如果区间在树上已经连通则说明可以判断该区间的差值,否则就进行合并操作,还有就是完全闭区间没法更新sum数组,所以我们可以进行一下,手动修改为左开右闭这样就方便很多,其余的一些细节详见代码注释。

由于笔者太菜了。。所以只能仿照某位大佬的代码重写了一遍。

代码:

#include<iostream>
#include<cstring>
#include<math.h>
#include<stdlib.h>
#include<cstring>
#include<cstdio>
#include<utility>
#include<algorithm>
using namespace std;
typedef long long ll;
const int Max = 200005;
const int mod = 1e9+7;
//pair<int ,int> arr[Max];
int t[Max];
//并查集
int pre[Max];
int sum[Max];//表示根到x的累加和
int Find(int x)//查询
{
    //这个代码的高明之处就在于Find过程中就将所需要的结点进行更新,并且每棵树的高度不会超过2,所以递归深度也很浅
    if(x != pre[x])
    {
        int t=pre[x];
        //将寻找根途中碰到的所有的结点都直接接到根上,这样可以降低递归深度,而且是下一步的基础
        pre[x]=Find(pre[x]);
        sum[x]+=sum[t];//利用递归函数的特性,更新sum数组
    }
    return pre[x];
}
void init( )//初始化
{
    for(int i=0; i<Max; i++)
    {
         pre[i] = i;
         sum[i] = 0;
    }
}
int n,m;
int main( )
{
    freopen("input.txt","r",stdin);
    while(cin>>n>>m)
    {
        init();
        int ans = 0;
        while(m--)
        {
            int ai, bi, si;
            scanf("%d %d %d",&ai, &bi,&si);
            ai--;//两个闭区间不好处理,转化为左开右闭
            int roota = Find(ai);//ai结点的树根
            int rootb = Find(bi);//bi节点的树根
            if(roota == rootb)
            {
                if((sum[ai]-sum[bi])!=si)
                    ans++;
            }
            else
            {
                pre[roota] = rootb;//将ai树接到bi树上
                //ai到roota的距离为sum[ai],bi到rootb的距离为sum[bi],ai到bi的距离为si,
                //画个简单的图,就可以理解roota到rootb的距离为什么是下面这个式子了
                sum[roota] = sum[bi]+si-sum[ai];//更新ai树根到bi树根的距离
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值