poj 1182 食物链

食物链

题意:"1 X Y",表示X和Y是同类;"2 X Y",表示X吃Y;输入N(1 <= N <= 50,000),(0 <= K <= 100,000)表示最多有N个动物,同时有K句话。

如果当前的话与前面的话不矛盾就说当前的话是正确的;(无罪判定)问这K句话中有几句是假话;

 

思路:很裸的种类并查集,只是里面穿插了三种关系,即同类,A吃B,B吃A;其实看了数组的范围[3*N]和x+N,x+2*N就知道思路了;即x吃x+N;类推

对于判定是否是同类时,不要直接求解,因为这与初始化违背;这是利用无罪假设,不冲突即可,即x不与y+N,y+2*N同类即可合并x和y;

同理判断x是否吃y,不要直接判断x是否与y+2*n在同一个集合中,而是看反面是否成立;每次处理合并三种关系即可;

ps:千万别开始就陷入思维定式,认为要将每种同类弄成0,1,2然后0吃1..这种,因为这种初始化很难,并且对于开始输入很多同类时,不知道给这些同类赋几;

Memory: 1280K        Time: 297MS
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
const int MAXN = 50050;
int f[MAXN*3];
int Find(int a)
{
    return a==f[a]?f[a]:f[a]=Find(f[a]);
}
bool sample(int a,int b)
{
    return Find(a) == Find(b);
}
void _union(int a,int b)
{
    a = Find(a),b = Find(b);
    f[a] = b;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int tot = 3*n,ans = 0;
    rep1(i,0,tot) f[i] = i;
    rep1(i,1,m){
        int D,x,y;
        scanf("%d%d%d",&D,&x,&y);
        if(x > n || y > n) ans++;
        else{
            if(D&1){
                if(sample(x+n,y) || sample(x+n+n,y)) ans++;
                else{
                    _union(x,y);
                    _union(x+n,y+n);
                    _union(x+n+n,y+n+n);
                }
            }
            else{
                if(sample(x,y) || sample(x+n+n,y)) ans++;
                else{
                    _union(x+n,y);
                    _union(x+n+n,y+n);
                    _union(x,y+n+n);
                }
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 

你可能感兴趣的:(poj 1182 食物链)