并查集-解决区间和纠错问题 hdu-3038

题目:多次给出信息,告诉你[a,b]区间的和,求多少个错误信息(错误信息不考虑)。

乍一看有点像线段树,但想想就发现这个并不能用线段树方便地解决。后来经提醒是并查集的一种经典题型。

把区间抽象为并查集的子节点和母根结点,子节点存放了到根节点的区间和。这样当引入一个新的区间,如果区间左右界根节点不同就一定不存在矛盾(有点种类并查集的意思,形象来看就是存在冗余区间用于调整),然后可以通过现存集合推导出子节点到根节点的区间和。如果根节点相同则要判断一下是否矛盾(画个图对线段加加减减就能推出公式了,文字不太好描述)。

这里注意一下数字是存在于端点上的,所以为了便于模拟,将小节点值--,或者将大节点++(注意不要溢出哦)。

#include <iostream>
#include <cstdio>
#define LL long long int
using namespace std;
int pre[200005];
LL val[200005];
int Find(int x)
{
    if(pre[x]==x) return x;
    int te=Find(pre[x]);
    val[x]+=val[pre[x]];
    return pre[x]=te;
}
void ini()
{
    int lx=200000;
    for(int i=0;i<=lx;i++)
        pre[i]=i,val[i]=0;
}
int main()
{
    cin.sync_with_stdio(false);
    int n,m;
    while(cin>>n>>m)
    {
        ini();
        int u,v,w,ans=0;
        for(int i=0;i<m;i++)
        {
            cin>>u>>v>>w;
            u--;
            int t[2]={Find(u),Find(v)};
            if(t[0]==t[1])
            {
                if(val[v]-val[u]!=w)
                    ans++;
            }
            else
            {
                pre[t[1]]=t[0];
                val[t[1]]=val[u]-val[v]+w;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LukeStepByStep/p/5934981.html