题目:https://www.luogu.org/problemnew/show/P2024
自己在做本题时最大的障碍就是:不会在一个集合的father改变时把相应的补集也跟着改变。
借鉴题解后,才明白原来就是把其补集也进行合并;由于fa数组在改变,不要定义一个变量为原来的find()在后面使用。
原来的乱七八糟代码:
#include<iostream> #include<cstdio> using namespace std; int n,k,s; int fa[2000005]; int find(int x) { if(x==fa[x])return x; return fa[x]=find(fa[x]); } int main() { scanf("%d%d",&n,&k); // for(int i=1;i<=n;i++) // fa[i]=i; int a,b,c; for(int i=1;i<=k;i++) { scanf("%d%d%d",&a,&b,&c); if(b>n||c>n) { s++;continue; } if(a==1) { if(!fa[b]) { if(!fa[c]) fa[b]=b,fa[c]=b; else fa[b]=c; } else if(!fa[c])fa[c]=b; else { int u=find(b); int v=find(c); if(u==find(v+n)||u==find(v+2*n)|| v==find(u+2*n)||v==find(u+n))s++; else fa[u]=v; } } if(a==2) { if(b==c) { s++;continue; } if(!fa[b])fa[b]=b; if(!fa[c])fa[c]=c; int u=find(b); int v=find(c); if(u==v||u==find(v+n)||v==find(u+2*n))s++; else fa[v]==u+n,fa[u]=v+2*n; } } printf("%d",s); return 0; }
改进后的代码(AC):
#include<iostream> #include<cstdio> using namespace std; int n,k,s; int fa[2000005]; int find(int x) { if(x==fa[x])return x; return fa[x]=find(fa[x]); } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n*3;i++)//!! fa[i]=i; int a,b,c; for(int i=1;i<=k;i++) { scanf("%d%d%d",&a,&b,&c); if(b>n||c>n) { s++;continue; } if(a==1) { // int u=find(b); // int v=find(c); if(find(b)==find(c+n)||find(b+n)==find(c))s++; else // fa[b]=c; { fa[find(b)]=fa[find(c)];//!!! fa[find(b+n)]=fa[find(c+n)];//!!! fa[find(b+2*n)]=fa[find(c+2*n)];//!!! } } if(a==2) { // int u=find(b); // int v=find(c); if(b==c||find(b)==find(c)||(find(c+n)==find(b)))s++; else // fa[b+n]=c,fa[c+2*n]=b; { fa[find(b+n)]=fa[find(c)];//!!! fa[find(c+2*n)]=fa[find(b)];//!!! fa[find(b+2*n)]=fa[find(c+n)];//!!! } } // for(int i=1;i<=n;i++) // printf("fa[%d]=%d ",i,fa[i]); // cout<<endl; } printf("%d",s); return 0; } /* 4 5 1 1 3 2 2 4 2 3 2 1 1 4 2 2 3 2 */