食物链(并查集)

动物王国中有三类动物 A,B,,这三类动物的食物链构成了有趣的环形。

A 吃 B,B 吃 C,C 吃 A。

现有 NN 个动物,以 1∼N 编号。

每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。

有人用两种说法对这 NN 个动物所构成的食物链关系进行描述:

第一种说法是 1 X Y,表示 X 和 Y 是同类。

第二种说法是 2 X Y,表示 X 吃 Y。

此人对 N 个动物,用上述两种说法,一句接一句地说出 KK 句话,这 KK 句话有的是真的,有的是假的。

当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

  1. 当前的话与前面的某些真的话冲突,就是假话;
  2. 当前的话中 X 或 Y比 N 大,就是假话;
  3. 当前的话表示 X 吃 X,就是假话。

你的任务是根据给定的 N 和 K 句话,输出假话的总数。

输入格式

第一行是两个整数 N 和 K,以一个空格分隔。

以下 KK 行每行是三个正整数 D,X,,两数之间用一个空格隔开,其中 D 表示说法的种类。

若 D=1,则表示 X和 Y 是同类。

若 D=2,则表示 X 吃 Y。

输出格式

只有一个整数,表示假话的数目。

数据范围

1≤N≤50000
0≤K≤100000

输入样例:

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

输出样例:

3
#include
using namespace std;

//规定到根节点距离%3为0的是同类,%3为一的可以吃根节点,%3为2的可以被根节点从吃
//只有一个根节点
const int sz=500010;

int p[sz],d[sz];//p[x]=x表示x的父节点是谁,d[]表示到父节点的距离
int n,k;

int find(int x)
{
    
    if(p[x]!=x)
    {
        int t=find(p[x]);//找到根节点
        d[x]+=d[p[x]];//压缩路径//压缩前表示到父节点的距离,压缩后表示到根节点的距离
        p[x]=t;
    }
    return p[x];
    
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) p[i]=i;//默认每个节点是自己的父亲,并且·d【i】==0;
                                 //表示自己是自己的同类;
    int ans=0;
    while(k--)
    {
        int j,x,y;
        cin>>j>>x>>y;
        if(x>n||y>n)ans++;
        else {
            int px=find(x),py=find(y);
            if(j==1){//距离%3不为0说明不是同类
                if(px==py&&((d[x]-d[y])%3))ans++;
                else if(px!=py)//不在一颗树
                {
                    p[px]=py;
                    d[px]=(d[y]-d[x] )%3; //(d[x]+?)%3=d[y]%3;
                                           // d[px]+?=d[y];?=d[y]-d[x];变成同类
                }
            }
             else 
            {
                if(px==py&&(d[x]-d[y]-1)%3)//x到根节点减去y到根节点的距离不为一就说明x不吃y
                ans++;
                else if(px!=py)//不在一颗树
                {
                    p[px]=py;
                    d[px]=(d[y]-d[x]+1);
                }
                
            }
            
        }
    }
    cout<

 食物链(并查集)_第1张图片

 食物链(并查集)_第2张图片

你可能感兴趣的:(模板题,c语言,算法,c++,数据结构)