1. 程式人生 > >【模板】帶權並查集 HDU 3038

【模板】帶權並查集 HDU 3038

具體學習參考https://blog.csdn.net/sunmaoxiang/article/details/80959300#commentBox

這篇部落格也是我覺得比較好理解的方法——向量法,具體體現在程式碼。

hdu 3038 區間和悖論問題

這裡寫圖片描述

假如說區間【fx,x】是之前建立的區間,他們之間和為sum[x],fx和x的聯絡可以用集合來儲存,同理【fy,y】也是如此。當給出了一個新的區間【x,y】時,且區間和為s。就產生了兩種情況了,如果fx == fy 那麼這兩個區間是有關聯的區間,也就是【x,y】之間的和是可以求出的。可以把這個圖看成一個向量。 區間【x,y】的和就是可以寫成sum[x] - sum[y]。判斷給出的s與向量法計算的區間和是否相等就可以判斷是否是悖論。 
當然如果fx != fy就需要建議新的區間關係。首先將fy指向fx,這代表fx是區間的左端點,計算sum【fy】= sum【x】- sum【y】+ s;這裡同樣用的是向量法。 
這樣建立聯絡與判斷悖論都可以表達了,接下來就是一些細節了,比如在更新區間的時候要進行路徑的壓縮,壓縮的過程中需要對權值進行更新,目的是使每個已知區間最大化。 

#include<iostream>
using namespace std;
const int maxn=200005;
int sum[maxn],pre[maxn];
int n,m;
void init()
{
    for(int i=0; i<=n; i++)
    {
        pre[i]=i;
        sum[i]=0;
    }
}
int find(int x)
{
    if(x==pre[x])
        return x;
    else
    {
        int root=find(pre[x]);
        sum[x]+=sum[pre[x]];
        return pre[x]=root;
    }
}
int main()
{

    while(cin>>n>>m)
    {
        init();
        int cnt=0;
        for(int i=0; i<m; i++)
        {
            int p,q,s;
            cin>>p>>q>>s;
            p--;
            int fp=find(p),fq=find(q);
            if(fp!=fq)
            {
                pre[fp]=fq;
                sum[fp]=sum[q]-sum[p]+s;
            }
            else if(sum[p]-sum[q]!=s)   cnt++;
        }
        cout<<cnt<<endl;
    }
    return 0;
}