1. 程式人生 > >並查集-How Many Answers Are Wrong(hdu3038)

並查集-How Many Answers Are Wrong(hdu3038)

題意:

現給出n個數字組成的序列,編號為1~n;

給出m個查詢,每個查詢的答案由a,b,s三個陣列成,表示從第a個數加到第b個數的和為s(對於a~b之間的和是s,其實可以理解成b比a-1大s);

但是其中有一些是有矛盾的(或者說錯誤的),求錯誤的查詢答案有多少個。

題解:

經典的帶權並查集問題;
1.sum[x]表示x-1到f[x]的和
2.sum[x] = sum[x]+sum[f[x]];//find_head()

3.並查集聯合父節點不同sum[fb] = s+sum[a]-sum[b];

4.並查集聯合父節點相同if(sum[b]-sum[a]) != s) return true;

 

  #include <iostream>
    #include <cstdio>
    #include <cstring> 
    using namespace std;
    const int N = 200005;
    int f[200005];
    int sum[200005];
    int find_head(int x)
    {
        int fx = x;
        if(x != f[x])
        {
            fx = find_head(f[x]);
            sum[x] = sum[x]+sum[f[x]];
            f[x] = fx;
        }
        return fx;
    }
    bool union_set(int a, int b, int s)//假話return true
    {
        int fa = find_head(a);
        int fb = find_head(b);
        if(fa != fb)
        {
            f[fb] = fa;
            sum[fb] = s+sum[a]-sum[b];
            return false;
        } 
        if((sum[b]-sum[a]) != s) return true;
        return false;
    }
    int main()
    {
        int n, m;
        while(scanf("%d%d",&n,&m) == 2)
        {
            int ans = 0;
            memset(sum, 0, sizeof(sum));
            for(int i = 0; i <= n; i++)
            {
                f[i] = i;
            }
            while(m--)
            {    
                int a, b, s;
                scanf("%d%d%d", &a,&b,&s);
                a--; //對於a~b之間的和是s,其實可以理解成b比a-1大s
                if(union_set(a, b, s))
                {
                    ans++;
                } 
            }
            cout<<ans<<endl;
        }
    
        return 0;
    }