题目:https://www.luogu.org/problemnew/show/2024
思路很重要。明确当“1”时只需a与b没有吃与被吃关系即可;当“2”时只需a与b不是同类也不是相反的吃的关系即可。
不需要很麻烦地想很多判断条件!
别忘了每次添加足够的新关系。
自己注意点:1.明确每个值仅有fa[ i ],没有“ i 本身”。故为了一开始的区分,给每个fa[ ]赋值成本身是很重要的;这就像给每个点打上了自己独特的标记。
自己曾试图用二维数组来表示补集,但问题在于别的点连接该点时,因为表示该点的脚标一样,故无法区分连的是该点的哪个集合。
——即使是同一个点,也该在 脚标 / 初值 上有所区分呢!
2.无需a+50000,只要a+n即可;
3.区分清楚变量自己和变量的值。如果用u来代表find(a),到时候改值不是改变u的值而是改变fa[ a ]的值!
#include<iostream> #include<cstdio> using namespace std; int n,k,fa[150005],a,b,c,fs; int find(int a) { if(fa[a]==a)return a; return fa[a]=find(fa[a]); } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=3*n;i++) fa[i]=i; for(int t=1;t<=k;t++) { scanf("%d%d%d",&c,&a,&b); if(a>n||b>n) { fs++; continue; } if(c==1) { int u=find(a+n); int v=find(b+n); int r=find(a+2*n); int e=find(b+2*n); int o=find(a); if(o==v||o==e) { fs++; continue; } fa[o]=fa[b]; fa[u]=fa[b+n]; fa[r]=fa[b+2*n]; } if(c==2) { int u=find(a); int v=find(b); int x=find(a+n); int y=find(a+2*n); int r=find(b+n); if(u==v) { fs++; continue; } if(u==r) { fs++; continue; } fa[x]=fa[b]; fa[u]=fa[b+2*n]; fa[y]=fa[b+n]; } } printf("%d",fs); return 0; }