1182 食物链

来源:互联网 发布:网络诈骗报警电话多少 编辑:程序博客网 时间:2024/05/04 11:32

第一行输入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
原创粉丝点击