网上大多数题解都是用的带权并查集方法,这个方法就不详细说了。
这里介绍另一种方法,个人觉得理解起来更容易。
首先,考虑如何保存动物之间的关系,自然想到用数组 eat[i] = j 来表示 i 吃 j 的关系,用并查集来保存已经确定是同类的动物。
但光是这样远远不够,我们还需要用三角环形来表示动物之间的关系。
******************
1
2 3
******************
这个三角形就表示 1 吃 3 ,3 吃 2 , 2 吃 1。
******************
4
5 6
******************
这个三角形表示 4 吃 6 ,6 吃 5 , 5 吃 4。
如果来了新关系 1 和 4 是同类 ,我们只需要把两个三角形合并成一个三角形:
******************
1,4
2,5 3,6
******************
这时候只需要用并查集把同类动物保存起来就行了,派每个并查集的祖宗放在三角形里。
但是一开始是没有三角形的,为了代码简单一点可以人为初始化生成三角形:
****************************
i
i+100000 i+50000
****************************
这样的话一开始就全是三角形,写代码只需要写三角形合并代码就行了。
思想大致就是这样,其他细节自行思考。
#include<cstdio> #include<algorithm> using namespace std; int fa[50005*3],eat[50005*3]; int f(int x){ if(fa[x]!=x) fa[x] = f(fa[x]); return fa[x]; } void link(int a,int b){ //三角形合并,a和b是同类 int tfa1=f(a),tfa2=f(b),Eat,n1,n2; for(int i=0;i<3;i++) { Eat = min(eat[tfa1],eat[tfa2]); n1 = f(eat[tfa1]); n2 = f(eat[tfa2]); if(tfa2<tfa1) fa[tfa1] = tfa2; else fa[tfa2] = tfa1; eat[tfa2] = eat[tfa1] = Eat; tfa1 = n1;tfa2 = n2; } return; } int main(){ int n,k,d,a,b,t,ta,tb,ans; scanf("%d%d",&n,&k); ans = 0; for(int i=1;i<=100000;i++) { eat[i]=i+50000; fa[i] = i; } for(int i=100001;i<=150000;i++) { eat[i]=i-100000; fa[i] = i; } for(int i=0;i<k;i++){ scanf("%d%d%d",&d,&a,&b); if(a>n||b>n) ans++; else if(d==1) if(f(eat[f(a)])==f(b)||f(eat[f(b)])==f(a)) ans++; else link(a,b); else if(d==2) if(f(a)==f(b)||f(eat[f(b)])==f(a)) ans++; else link(eat[f(a)],b); } printf("%d\n",ans); return 0; }