AcWing 240. 食物链 (边带权并查集、同余)

240. 食物链

  • 建模
    巧妙的建模,由于题目中只有三种动物,并且这三种动物的食物链构成了一个,而这种环和取模后循环有着密切的关系。
    具体的:
    将所有的动物合并到一个并查集里,
    现在有两个点 x , y x,y x,y
    • d [ x ] − d [ y ] ≡ 0 ( m o d    3 ) d[x]- d[y]\equiv 0(mod\ \ 3) d[x]d[y]0(mod  3),说明, x x x y y y是同类。
    • d [ x ] − d [ y ] ≡ 1 ( m o d    3 ) d[x]- d[y]\equiv 1(mod\ \ 3) d[x]d[y]1(mod  3),说明, x x x y y y
    • d [ x ] − d [ y ] ≡ 2 m o d    3 ) d[x]- d[y]\equiv 2mod\ \ 3) d[x]d[y]2mod  3), 说明, y y y x x x

所以,在处理两种动物时,先判断它们已经有没有关系,如果有,判断是否发生矛盾;
如果没有,去构建它们之间的关系。

  • 边带权的并查集的处理要点
    • 路径压缩时,注意同步更新距离。
    • 合并永远发生在两个集合的根节点上,所以需要自己计算出二者之间的距离。
#include<stdio.h>
using namespace std;

const int N = 50010;
int f[N], d[N], n, k;

int find(int x){
    
    
    if(f[x]!=x){
    
    
        int root = find(f[x]);
        d[x] += d[f[x]];
        f[x] = root;
    }
    return f[x];
}

int main(){
    
    
    scanf("%d%d",&n,&k);
    int ans = 0;
    for(int i=1;i<=n;i++) f[i] = i;
    while(k--){
    
    
        int t,x,y;
        scanf("%d%d%d",&t,&x,&y);
        if(x<1 || x>n || y<1 || y>n) ans++;
        else{
    
    
            int px = find(x);
            int py = find(y);
            if(t==1){
    
    
                if(px==py){
    
     // 之前的信息确定它们之间是有关系的
                    if( (d[x]-d[y])%3 ) ans++;
                }else{
    
          // 目前还没有关系,即将合并
                    f[px] = py;      //合并永远只发生在根节点上
                    d[px] = ( (d[y]-d[x])%3+3)%3;
                }
            }else if(t==2){
    
    
                if(px==py){
    
    
                    if( ((d[x]-d[y])%3+3)%3 != 1 ) ans++;
                }else{
    
    
                    f[px] = py;
                    d[px] = ((d[y]-d[x]+1)%3+3)%3;
                }
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/108782494
今日推荐