带权并查集

带权并查集 概念:

  • 就是合并的时候加个权值,找祖父时加个权值。
  • 对于闭区间的时候一定要变成开区间 a-1  ->B   很关键  下面 一定要 a--;将这个东西给连接起来。( 】

   应用: 针对性的解决 一个很长的区间问题。 给出很多的小区间 ,来判断 这些小区间很前面的小区间冲不冲突

 

 

int find(int a)
{
    if(a==fa[a]) return a;
    int b=fa[a];
    fa[a]=find(fa[a]);
    val[a]+=val[b];
    return fa[a];
}
View find fa

 

        for(ri i=1;i<=n;i++)
    {
        fa[i]=i;
    }
    for(ri i=1;i<=m;i++)
    {
        int a,b,c;
        read(a);read(b);    read(c);
        if(a>b) swap(a,b);
        a--; // 左开右闭, a--,为什么这么重要就找到了,下面的东西,  
        int l=find(a),r=find(b);
        if(l==r)
        {
            if(c==val[a]-val[b]) printf("yes\n");
            else printf("no\n");
        }
        else
        {
            fa[l]=r;
            val[l]=val[b]+c-val[a];
        }
    }
View process

 

后记

  • 一定注意要 a--,区间是左开右闭的,其他的处理无脑用就行了,
  • 记得预处理

 

 

例题:

HDU-3038-How Many Answers Are Wrong

这个题题目的废话比较多,这里简述一下大意:有M个数,不知道它们具体的值,但是知道某两个数之间(包括这两个数)的所有数之和,现在给出N个这样的区间和信息,需要判断有多少个这样的区间和与前边已知的区间和存在矛盾。例如给出区间和[1,4]为20,[3,4]为15,再给出[1,2]为30,显然这个[1,2]的值就有问题,它应该为20-15=5。
View Problem

  代码:

#include <bits/stdc++.h>
using namespace std;
#define ri register int 
const int N=202000;
const int M=40000;
int n,m;
int val[N],fa[N],ans;
int find(int a)
{
    if(a!=fa[a])
    {
        int t=fa[a];
        fa[a]=find(fa[a]);
        val[a]+=val[t]; // 跟新 这个节点到 祖父的 权值 
    }
    return fa[a];
}
int main(){
    while(~scanf("%d%d",&n,&m))
    {
        ans=0;memset(val,0,sizeof val);
        for(ri i=0;i<=n;i++) fa[i]=i;
        for(ri i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            a--;
            int l=find(a);
            int r=find(b);
            if(l!=r)
            {
                fa[l]=r;
                val[l]=-val[a]+c+val[b];   //跟新权值 
            }
            else
            {
                if(val[a]-val[b]!=c) ans++;// 解决问题 小的节点到 祖父的权值 大 
            }
        }
        printf("%d\n",ans);
    }
}
View Code

题目:相见减做判断, 找规律,本身就是开区间

View Problem

代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
const int M = 10005;
const int N = 50050;
#define ri register int 
int fa[N],val[N];
int find(int a)
{
    if(a!=fa[a])
    {
        int t=fa[a];
        fa[a]=find(fa[a]);
        val[a]=(val[a]+val[t])%3;
    }
    return fa[a];
}
int n,m,ans;
int main(){
    scanf("%d%d",&n,&m);
    for(ri i=1;i<=n;i++) fa[i]=i;
    for(ri i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&c,&a,&b);
        if(a>n||b>n||(a==b&&c==2)) 
        { 
         ans++;continue;
        }
        int l=find(a);
        int r=find(b);
        if(l!=r)
        {
            fa[l]=r;
            val[l]=(val[b]+c-1-val[a]+3)%3;
        }
        else{
            if((val[a]-val[b]+3)%3!=(c-1)) ans++;
        }
    }
    printf("%d\n",ans);
}  
View Code

 

posted @ 2019-10-30 15:29  VxiaohuanV  阅读(171)  评论(0编辑  收藏  举报