算法图论学习-带权并查集

91 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

带权并查集

带权并查集是并查集的一种,在我们的基础并查集中我们只能通过并查集的操作获取到当前点的父亲,而带权并查集就增加了一个权值,这个权值表达的是当前节点与他父亲之间权值的关系

例题[食物链]

这是一道很经典的题目可以用拓展域并查集和带权并查集来做这里我们使用带权并查集的方法来写这道题目

image.png

根据题意我们可以推导出三个关系,我们将这三个关系用数字表示

  • A和B是同类 w = 0
  • A吃B w = 1
  • B吃A w = 2
    我们的w表示的是当前结点与他父亲结点之间的关系,但是如果A和B一开始不在一个连通块中我们怎么将他们合并起来呢? 如图

capture-2022-11-27-18-57-46.jpg

这样我们就能推导出关系根据推导出的关系我们就可以进行代码的书写了

Code

const int N = 2e5 + 10;
int f[N], w[N];
int find(int x) {
    if(f[x] == x) return f[x];
    int fa = f[x];
    f[x] = find(fa);
    w[x] = (w[x] + w[fa]) % 3;
    return f[x];
}
void solve()
{
   int n, k; cin >> n >> k;
   for(int i = 1; i <= n; i++) f[i] = i, w[i] = 0;
   int res = 0;
   for(int i = 1; i <= k; i++) {
     int op, x, y; cin >> op >> x >> y;
     if((x > n || y > n) || (op == 2 && x == y)) {
        res ++; continue;
     }
     if(op == 1) {
         int fa = find(x), fb = find(y);
         if(fa != fb) {
            f[fa] = fb; w[fa] = (3 + 0 - w[x] + w[y]) % 3;
         }else {
            if(w[x] != w[y]) res ++;
         }
     }else {
        int fa = find(x), fb = find(y);
         if(fa != fb) {
            f[fa] = fb, w[fa] = (3 + 1 - w[x] + w[y]) % 3;
         }else {
            if(((3 + w[x] - w[y]) % 3 )!= 1) res ++;
         }
     }
   }
   cout << res << endl;
}