码迷,mamicode.com
首页 > Windows程序 > 详细

# [acwing 240] 食物链 [并查集]

时间:2020-01-26 14:42:35      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:构造   ++i   print   描述   using   namespace   合并   name   win   

[acwing 240] 食物链 [并查集]

传送门

题意

ABC三种动物,食物链构成一个环形,,给出M个关于彼此关系的描述,判断有多少个假话。

  • 1 X Y表示同类
  • 2 X Y表示X吃Y

思路

本题是并查集的一种比较新颖的用法,并查集一般用来维护集合,但是在这里主要是使用路径压缩来维护点和根之间的距离。

动物之间有三种关系(同类,捕食,被捕食),并且食物链构成环,那么可以使用和根之间的距离模3来区分三种关系,这里并不严格划分集合,主要是借助了并查集中的路径压缩。

技术图片

红色的线是不存在的,只是为了方便理解。图中的关系是:

  • 2吃1 ,3吃2,4吃3,6吃4,5吃1。
  • 其中3被1和4吃,那么1和4是同类(因为食物链是环形的,吃同一种动物的就是同类),1和4到1的距离模3都是0。
  • 2,5,6是同类,模3都是1,都是1的捕食者

使用d[]维护节点x到父节点的距离,路径压缩时只要更新d[]的值

Code:

#include <iostream>
using namespace std;
const int maxn=5e4+10;
int n,m;
int p[maxn],d[maxn];
inline int find(int x){
    if(p[x]==x)return x;

    int t=find(p[x]);
    d[x]+=d[p[x]];//x节点到父节点p[x]的距离加上父节点到父父节点的距离,递归可得到根节点的距离
    p[x]=t;//最终父节点更新成根节点
    return p[x];
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i)p[i]=i;

    int ans=0;
    for(int i=0,r,x,y;i<m;++i){
        scanf("%d %d %d",&r,&x,&y);
        if(x>n||y>n)ans++;
        else {
            int px=find(x),py=find(y);
            if(r==1){
                if(px==py&&(d[x]-d[y])%3)ans++;//同一颗树上,同类的动物模3同余
                else if(px!=py){//不在一个集合,无法判断是错误,那么是正确,那么构造同类关系
                    p[px]=py;
                    //合并的时候d[px]+d[x]和d[y]模3同余,即(d[px]+d[x]-d[y])%3==0
                    //可以认为d[px]=d[y]-d[x]。其他关系同理
                    d[px]=d[y]-d[x];
                }
            }
            else {//x吃y
                if(px==py&&(d[x]-d[y]-1)%3)ans++;
                else if(px!=py){
                    p[px]=py;
                    d[px]=d[y]+1-d[x];
                }
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

# [acwing 240] 食物链 [并查集]

标签:构造   ++i   print   描述   using   namespace   合并   name   win   

原文地址:https://www.cnblogs.com/sstealer/p/12234102.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!