[JZOJ3385] [NOIP2013模拟] 黑魔法师之门 解题报告(并查集)
题目大意:有n个点,进行m次加边操作,每次操作之后输出当前图中的子集是一个或多个环的个数
题解:
考虑在第一次加边之后我们得到了一条“线段”,我们将其看成是一棵树(事实上它就是树)。发现当我们把树变成一颗环基树的时候就一定会产生一个环。在不断的加边的过程中,我们发现
每一个非树上边的子集都对应了一个我们统计的子图。那么我们的答案就是2^t-1,t就是非树上边的条数(没有树上边的时候没有环,因此减1)。那么怎么搞出树上边的条数呢?考虑用并查集维护,支持合并操作。
值得注意的是,我们统计的是子集的个数,而不是环的个数
代码非常的好写
#include <iostream> #include <cstdio> using namespace std; const int N=2e5+50; const int P=1000000009; int n,m,sum; int fa[N]; long long ans=1; int read() { int x=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0') {if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} return x*f; } int find(int k) { if (fa[k]!=k) fa[k]=find(fa[k]); return fa[k]; } int main() { n=read();m=read(); for (int i=1;i<=n;i++) fa[i]=i; for (int i=1;i<=m;i++) { int x=read(),y=read(); int fx=find(x),fy=find(y); if (fx==fy) ans=ans<<1; else fa[fx]=fy; ans%=P; printf("%lld\n",ans-1); } return 0; }
星星之火,终将成燎原之势