标签:并查集
食物链3
种类并查集,比普通并查集多开一个数组rank[i],他是表示 far[i] 对i的关系。
这题里有三种关系 吃 被吃 同类 我分别定为1 2 0;
种类并查集更新什么的,和普通并查集也差不多。find都是递归更新,要压缩路径。
除了模版之外,要推的有下面两点
1.
模版当中 find 函数的 rank[n]=(rank[tem]+rank[n])%3; 这句。 n表示当前的点,要知道他和他爷爷的关系,可以通过 他和他父亲的关系 rank[tem]和 他和他父亲的关系 rank[n]来推。
2.
模版中rank[bb]=(rank[a]-rank[b]+relation+3)%3; 这句。 bb表示b的祖先。要把bb接上aa,作为aa的儿子。 画出 四个点,分别知道 aa 对a 的关系rank[a], bb对b的关系rank[b],还知道a对b的关系relation。 然后就可以推出aa对bb的关系了。+3是防止出现负数。
画出来的图可以看出。求一条边的关系,就是把和这条边相反方向的rank加上 再减去相同方向的rank 再取模就可以了。
#include<stdio.h>
#define max 100010
int far[max];
int rank[max];
int ans;
void inti()
{
int i;
for(i=1; i<=max; i++)
{
far[i]=i;//自己独自是一棵树;
rank[i]=0;//开始定义偏移量为0;
}
}
int find_set(int n)//路径压缩 0表示同类 1表示上吃下 2表示下吃上
{
int tem;
if(n==far[n])
return n;
tem=far[n];//tem 找到前驱。
far[n]=find_set(tem);
rank[n]=(rank[tem]+rank[n])%3;
return far[n];
}
void unit(int a,int b,int relation)//0同类 1 a吃b
{
int aa,bb;
aa=find_set(a);
bb=find_set(b);
if(aa==bb)
{
if((rank[a]+relation-rank[b]+3)%3==0)
{
return ;
}
else
{
ans++;
return ;
}
}
far[bb]=aa;
rank[bb]=(rank[a]-rank[b]+relation+3)%3;
}
int main()
{
int T;
int n,m,nn,mm;
char a;
scanf("%d%d",&n,&m);
inti();
ans=0;
for(int i=0;i<m;i++)
{
int d,x,y;
scanf("%d%d%d",&d,&x,&y);
if(x>n||y>n||(d==2&&x==y))
{
ans++;
continue;
}
else if(d==1)
unit(x,y,0);
else if(d==2)
unit(x,y,1);
}
printf("%d\n",ans);
return 0;
}
/*
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
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
*/
标签:并查集
原文地址:http://blog.csdn.net/u013532224/article/details/43272021