AC日记——食物链 codevs 1047

1074 食物链

 

2001年NOI全国竞赛

 时间限制: 3 s
 空间限制: 64000 KB
 题目等级 : 钻石 Diamond
 
 
 
题目描述 Description

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

现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。   

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

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

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

此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。   

1) 当前的话与前面的某些真的话冲突,就是假话;   

2) 当前的话中X或Y比N大,就是假话;   

3) 当前的话表示X吃X,就是假话。   

你的任务是根据给定的N(1<=N<=50,000)和K句话(0<=K<=100,000),输出假话的总数。

输入描述 Input Description

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

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

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

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

输出描述 Output Description

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

样例输入 Sample Input

100 7

1 101 1

2 1 2

2 2 3

2 3 3

1 1 3

2 3 1

1 5 5

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

输入文件  

 对7句话的分析 100 7

1 101 1  假话

2 1 2    真话

2 2 3    真话

2 3 3    假话

1 1 3    假话

2 3 1    真话

 1 5 5    真话

NOI 2001 食物链(eat)

思路:

  并查集;

  怎么做呢?

  有人说要用带权并查集

  然而我是蒟蒻我不会

  我们要开三倍的n的father数组

  i表示与i同类的集合

  i+n表示i可以吃的集合

  i+n+n表示i+n可以吃且可以吃i的集合

  然后每次判断是否是符合已有的真话

  不符合ans++

  符合就作为一条新的真话

来,上代码:

#include <cstdio>

#define maxn 50001
#define maxm 100001

using namespace std;

class Finding {
    private:
        int n,m,f[maxn*3],if_z,ans;
        
        char Cget;
        
        inline void read_int(int &now_)
        {
            now_=0,if_z=1,Cget=getchar();
            while(Cget>'9'||Cget<'0')
            {
                if(Cget=='-') if_z=-1;
                Cget=getchar();
            }
            while(Cget>='0'&&Cget<='9')
            {
                now_=now_*10+Cget-'0';
                Cget=getchar();
            }
            now_*=if_z;
        }
        
    public:
        Finding()
        {
            read_int(n),read_int(m);
            for(int i=1;i<=n*3;i++) f[i]=i;
            int type,x,y;
            for(int i=1;i<=m;i++)
            {
                read_int(type),read_int(x),read_int(y);
                if(x>n||y>n)
                {
                    ans++;
                    continue;
                }
                if(type==1)
                {
                    if(If_same(x,y+n)||If_same(x,y+n+n))
                    {
                        ans++;
                        continue;
                    }
                    else
                    {
                        Merge(x,y);
                        Merge(x+n,y+n);
                        Merge(x+n+n,y+n+n);
                    }
                }
                else
                {
                    if(If_same(x,y)||If_same(x+n+n,y))
                    {
                        ans++;
                        continue;
                    }
                    else
                    {
                        Merge(x+n,y);
                        Merge(x+n+n,y+n);
                        Merge(x,y+n+n);
                    }
                }
            }
            printf("%d
",ans);
        }
        
        int Find(int x)
        {
            if(x==f[x]) return x;
            f[x]=Find(f[x]);
            return f[x];
        }
        
        bool If_same(int x,int y)
        {
            if(Find(x)==Find(y)) return true;
            else return false;
        }
        
        void Merge(int x,int y)
        {
            x=Find(x),y=Find(y);
            if(x!=y) f[x]=y;
        }
};
class Finding do_;

int main()
{
    return 0;
}
原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6296597.html