入门OJ 4192: [Noip模拟题]黑魔法师之门 (并查集)

题目

Description

applepi被囚禁的地点只有一扇门,当地人称它为“黑魔法师之门”。这扇门上画着一张无向无权图,而打开这扇门的密码就是图中【每个点的度数大于零且都是偶数】的子图的个数对1000000009取模的值。此处子图 (V, E) 定义为:点集V和边集E都是原图的任意子集,其中E中的边的端点都在V中。但是Vani认为这样的密码过于简单,因此门上的图是动态的。起初图中只有N个顶点而没有边。Vani建造的门控系统共操作M次,每次往图中添加一条边。你必须在每次操作后都填写正确的密码,才能够打开黑魔法师的牢狱,去拯救伟大的领袖applepi。

Input

第一行包含两个整数NM

接下来M行,每行两个整数AB,代表门控系统添加了一条无向边 (A, B)

N≤200000M≤300000

Output

输出一共M行,表示每次操作后的密码。

题解

一道海星的并查集

主要难度在理解题意上了

代码

#include <cstdio>
#include <vector>
using namespace std;
class UnionFind {
 private:
  int quantity;
  vector<int> union_;
 public:
  UnionFind(const int maximum = 1) {
    union_.assign(maximum + 10, 0);
    quantity = maximum;
    for (register int i(1); i <= maximum; ++i) {
      union_[i] = i;
    }
  }
  inline void Assign(const int &maximum) {
    union_.clear();
    union_.assign(maximum + 10, 0);
    quantity = maximum;
    for (register int i(1); i <= maximum; ++i) {
      union_[i] = i;
    }
  }
  inline int Find(const int &x) {
    return union_[x] == x ? x : union_[x] = Find(union_[x]);
  }
  inline void Merge(const int &u1, const int &u2) {
    const int tmp1(this->Find(u1)), tmp2(this->Find(u2));
    union_[tmp2] = tmp1, union_[u2] = tmp1;
  }
};
UnionFind unions;
const int kMod(1000000009);
int n, m, x, y, ans(1);
int main(int argc ,char **argv) {
  scanf("%d %d", &n, &m);
  unions.Assign(n);
  while (m--) {
    scanf("%d %d", &x, &y);
    if (unions.Find(x) != unions.Find(y))unions.Merge(x, y);
    else ans *= 2;
    if (ans > kMod) ans -= kMod;
    printf("%d\n", ans - 1);
  }
  return 0;
}
posted @ 2018-08-25 09:03  Acenaphthene  阅读(183)  评论(0编辑  收藏  举报