1182 食物链

第一行输入n,k代表n个动物,k条语句
接下来k行
每一行输入d,x,y
d=1代表xy为同类
d=2代表x吃y
要求输出假话数目
问>0<何为假话
1.x或y大于n
2.现在输入的语句与之前语句矛盾
3.自己吃自己
每输入一个询问,就判断x和y是否都被放入同一集合中(也就是是否已确定关系),如果以确定,判断比较,未确定,添加。
确定关系
rel[i]=0(d=1 1-1)
i与根节点为同类
rel[i]=1(d=2 2-1)
i吃根节点
rel[i]=2
根节点吃i
解释三个公式:
公式1:>0<
–rel[x]=(rel[x]+rel[fa])%3
–由向量即可证明
公式2:>0<
–判断所给语句是否符合xy关系
–rel[x]==((d-1)+rel[y])%3
–d-1代表xy之间的关系
–由公式一易证此公式
公式3:>0<
–在将x所在的集合并入y所在集合时^_^
–rel[fx]=(rel[y]+(d-1)-rel[x]+3)%3
–由公式二易证
^_^

#include<iostream> //带偏移量的并查集,重点是如何路径压缩 
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int f[50010];//此节点的父节点 
int rel[50010];//此节点与其父节点的距离**rel=0同类,rel=1此节点吃父节点,rel=2此节点被其父节点吃 
int find(int x){//路径压缩 
    if(f[x]==x)
        return x;
    int fa=f[x];
    f[x]=find(f[x]);
    rel[x]=(rel[x]+rel[fa])%3return f[x];
}
void add(int d,int x,int y){
    int fx,fy;
    fx=find(x);
    fy=find(y);
    if(fx==fy)
        return;//如果两个节点的最终父节点是一个,则不用进行任何操作 
    //如果不相等将fx的父节点设为y的父节点
    f[fx]=fy;
    rel[fx]=(rel[y]+(d-1)-rel[x]+3)%3;//将x所在的集合合并到y的集合 
}
bool judge(int d,int x,int y){
    int fx,fy;
    fx=find(x);
    fy=find(y);
    if(fx!=fy)
        return true;
    if(rel[x]==((d-1)+rel[y])%3) 
        return true;
    return false;
}
int main(){
    int n,k,ans=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){//初始化 
        f[i]=i;
        rel[i]=0;//此节点与自己为同类 
    }
    for(int i=1,d,x,y;i<=k;i++){
        scanf("%d%d%d",&d,&x,&y);
        if(x>n||y>n||(d==2&&x==y))//如果输入动物不在n范围内或自己吃自己那么一定是假话 
            ans++;
        else if(judge(d,x,y)==false)
            ans++;
        else
            add(d,x,y);
    }
    cout<<ans<<endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值