I - How Many Answers Are Wrong 带权并查集 (存在区间)

https://vjudge.net/contest/375481#problem/I

这道题是一个带权的并查集(需要复习)

总体思路:1.由于无法直接通过两个点之间距离再次出现来判断v是否相等  只能借助于并查集间的联代关系 创造一个中间节点 即 祖宗节点;

2.先对并查集进行初始化,同时对sum也进行初始化(sum代表的是 点i到根节点的距离)

3.特判 1如果两个点不是一个集合的点 需要将两个点连接 注意:连接的时候会造成sum【x】(在此处x是a点的祖宗节点)的改变 因为x指向了y点 x到根节点的距离需要重新定义

同时这是属于区间的更新 区间的更新有一个性质 半开区间性质 (a,b]+(b,c]=(a,c] 因此我们去点要取到开区间上那个点 即做a--的操作

4.上次sum【x】的更新也会影响到它的子节点的距离 ,它的子节点的距离在find中有 即sum【x】+=sum【f】,这个会在 x下次出现的时候自动更新 (在sum【x】更新后的事) 存疑

5.特判2 如果两个点是一个集合 ,直接进行减法 ,判断是否等于v,否,则错误,ans++。注意这里a是比b远的,所以用a-b ;

 

#include
using namespace std;
const int N=5e5+10;
int p[N],sum[N];
int find(int x)
{
    if(p[x] != x)
    {
        int f = p[x];
        p[x] = find(p[x]);
        sum[x] += sum[f];
    }
    return p[x];
}

int main()
{
    int n,m;
   while(~scanf("%d%d",&n,&m))
   {
    int ans=0;
    for(int i=0;i<=n;i++)
    {
        p[i]=i;
        sum[i]=0;
    }
    int a,b,v;
     while(m--)
        {
            
            scanf("%d%d%d", &a, &b, &v);
            a-=1;
            int x = find(a);
            int y = find(b);
            if(x != y)
            {
                p[x] = y;
                sum[x] = sum[b] - sum[a] + v;
            }
            else 
            {
                if(sum[a] - sum[b] != v) ans++;
            }
        }
        printf("%d\n", ans);
   }

    return 0;
}

 

你可能感兴趣的:(算法)