HDU 3038 How Many Answers Are Wrong

题意:
有一个长度为n的数列,一共有m句话,每句话都有a,b,c,代表在[a,b]区间内的数的和。其中有一些话是真的,有一些话是假的(与原来的事实冲突的),问给出这些话中有几句是假的。
思路:
是一道并查集的题目。
其中用uf[n]代表n的父亲,用dis[n]代表n到uf[n]之间的数字之和。
那么对于f1 = find(a), f2 = find(b).
如果f1 < f2,那么会有两种情况。
第一种:a <= b <= f1 <= f2:
那么uf[f1] = f2,就有
dis[f1] = dis[b] - (dis[a] - c);
第二种:a <= f1 <= b <= f2:
和上面相同。
如果f1 > f2,那么只会有一种情况:a <= b <= f2 <= f1
那么uf[f2] = f1,就有
dis[f2] = dis[a] - dis[b] - c;
如果f1 == f2,那么就可以通过dis[a] - dis[b] 是否等于c来判断话的对错。
Code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<stack>
#include<list>
#include<map>
#include<set>

#define TEST

#define LL long long
#define Mt(f, x) memset(f, x, sizeof(f));
#define rep(i, s, e) for(int i = (s); i <= (e); ++i)
#ifdef TEST
    #define See(a) cout << #a << " = " << a << endl;
    #define See2(a, b) cout << #a << " = " << a << ' ' << #b << " = " << b << endl;
    #define debug(a, s, e) rep(_i, s, e) {cout << a[_i] << ' ';} cout << endl;
    #define debug2(a, s, e, ss, ee) rep(i_, s, e) {debug(a[i_], ss, ee)}
#else
    #define See(a)
    #define See2(a, b)
    #define debug(a, s, e)
    #define debug2(a, s, e, ss, ee)
#endif // TEST

const int MAX = 2e9;
const int MIN = -2e9;
const double eps = 1e-8;
const double PI = acos(-1.0);

using namespace std;

const int N = 200000 + 5;

int uf[N], dis[N];

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

int fd(int n)
{
    if(n != uf[n])
    {
        int t = uf[n];
        uf[n] = fd(uf[n]);
        dis[n] += dis[t];
    }
    return uf[n];
}

int make(int a, int b, int c)
{
    int f1 = fd(a);
    int f2 = fd(b);
    if(f1 == f2)
    {
        if(dis[a] - dis[b] == c)
        {
            return 0;
        }
        return 1;
    }
    else if(f1 < f2)
    {
        uf[f1] = f2;
        dis[f1] = dis[b] - (dis[a] - c);
    }
    else
    {
        uf[f2] = f1;
        dis[f2] = dis[a] - dis[b] - c;
    }
    return 0;
}

int main()
{
    int n, q;
    while(~scanf("%d%d", &n, &q))
    {
        init(n);
        int ans = 0;
        while(q--)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            ans += make(a - 1, b, c);//这里为[a - 1, b]可以使相邻的区间连接在一起。
        }
        printf("%d\n", ans);
    }
    return 0;
}
/*
3 10
1 3 10
1 1 1
1 2 3
3 3 8
3 3 7
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值