poj1182(并查集)

 

题目链接

分析:根据分析,关系的递推满足由[a,b]~[b,c]得:[a,c]=([a,b]+[b,c])%3;[a,d]=([a,b]+[b,c]+[c,d])%3.由rank数组表示关系

    0 - 这个节点与它的父节点是同类 

    1 - 这个节点被它的父节点吃 

    2 - 这个节点吃它的父节点。 

则:当 d = 1的时候,( d - 1 ) = 0,也就是我们制定的意义  

     当 d = 2的时候,( d - 1 ) = 1,代表Y被X吃,也是我们指定的意义。

逆推根节点与Y的关系 

这部分也是穷举法推出来的,我们举例: 

父相对于子的relation(即假如子是父的父节点,那么父的relation应该是什么,因为父现在是根节点,所以父.relation = 0,我们只能根据父的子节点反推子跟父节点的关系) 

         0             ( 3 - 0 ) % 3 = 0 

         1(父吃子)   ( 3 - 1 ) % 3 = 2 //父吃子 

         2(子吃父)    ( 3 - 2 ) % 3 = 1 //子吃父,一样的

因此合并时,x,y,a(x的根节点),b(y的根节点),d(x与y的关系),rank[x](x与a的关系),rank[y](y与b的关系)rank[b](b与a的关系)则:

[b,a]=([b,y]+[y,x]+[x,a])%3.而[b,y]=(3-[y,b])%3.因此rank[b]=(3-rank[y]+d+rank[x]).

#include <cstdio>

#include <cstring>

#include <string>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <queue>

#include <cstdlib>

#include <stack>

#include <vector>

#include <set>

#include <map>

#define LL long long

#define mod 100000000

#define inf 0x3f3f3f3f

#define eps 1e-9

#define N 50010

#define FILL(a,b) (memset(a,b,sizeof(a)))

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

#define PII pair<int,int>

using namespace std;

int fa[N],rank[N];

int find(int x)

{

    if(x==fa[x])return x;

    int pa=fa[x];

    fa[x]=find(fa[x]);

    rank[x]=(rank[x]+rank[pa])%3;

    return fa[x];

}

void merge(int a,int b,int x,int y,int d)

{

    fa[b]=a;

    rank[b]=(3-rank[y]+d-1+rank[x])%3;

}

int main()

{

    int n,m;

    scanf("%d%d",&n,&m);

    for(int i=1; i<=n; i++)

    {

        fa[i]=i;

        rank[i]=0;

    }

    int ans=0;

    while(m--)

    {

        int d,x,y;

        scanf("%d%d%d",&d,&x,&y);

        if(x>n||y>n||(d==2&&x==y))ans++;

        else

        {

            int a=find(x);

            int b=find(y);

            if(a!=b)merge(a,b,x,y,d);

            else

            {

                if((rank[y]+3-rank[x])%3!=d-1)ans++;

            }

        }

    }

    printf("%d\n",ans);

}
View Code

 

你可能感兴趣的:(poj)