带权并查集——食物链

并查集是常见而且好用的一种数据结构。原因在于代码简练而且方便维护各种额外信息。带权并查集就是并查集的一种应用方式。原理其实就是普通并查集额外维护了一个结点的权数组。

例题:

本题的关系有三层 -> a -> b -> c -> ,但不同的是本题的关系是有向的,也就是说a和b如果是敌对关系,那么b和a就不是敌对关系。

关系传递的本质实际上是向量的运算。
还是设 d[x] 表示 x 与 fa[x] 的关系,0 代表是同类,1 代表是x吃fa[x], 根据关系图自然2就代表x被fa[x]吃。

#include<iostream>
using namespace std;

const int N = 500010;

int p[N];
int d[N];//带权并查集的权值0 1 2 三个值分别表示是同类,吃根节点,和被根节点吃;
int n,m,k,a,b;
int find(int x)
{
    if(p[x] == x) return x;
    int r = find(p[x]);
    d[x] += d[p[x]];
    return p[x] = r;
}


int main(){
    cin>>n>>m;
    for(int i = 0 ; i <= n ; i++){
        p[i] = i;
    }
    int res = 0;
    for(int i = 0 ; i < m ; i ++){
        cin>>k>>a>>b;

        if(a>n || b>n){
            res++;continue;    
        } 
        else if(k == 2 && a == b){
            res++;continue;
        }else{
            int x = find(a);int y = find(b);
            int t = 0;
            if(k==2) t = 1;
            if(x == y){
                if(  (((d[a] - d[b]) % 3) + 3) % 3 != t ){
                    res ++;

                }
            }else{
                p[x] = y;
                d[x] = d[b] - (d[a] - t);
            }

        }
    }
    cout<<res<<endl;


    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Flydoggie/p/12283513.html