Problem p00967 (C++)

Buggy submission (status: Runtime Error):
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <complex>

#include <cassert>
#include <functional>

typedef long long ll;
using namespace std;

#define debug(x) cerr << #x << " = " << (x) << endl;

#define mod 1000000007              // 1e9+7(prime number)
#define INF 1000000000              // 1e9
#define LLINF 2000000000000000000LL // 2e18
#define SIZE 100020

/* UnionFind */

struct UnionFind {
  vector<int> data, tree_size;
  UnionFind(int s) : data(s, -1), tree_size(s, 1) {}

  int root(int x) {
    if (data[x] == -1)
      return x;
    return data[x] = root(data[x]);
  }

  bool set(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    data[y] = x;
    tree_size[x] += tree_size[y];
    tree_size[y] = 0;
    return true;
  }

  bool check(int x, int y) {
    x = root(x);
    y = root(y);
    return x == y;
  }

  int size(int x) { return tree_size[root(x)]; }
};

vector<pair<int, int>> G[SIZE];
bool tree[SIZE];
int u[SIZE], v[SIZE];
int visited[SIZE];
int depth[SIZE];

bool dfs(int now, int back = -1, int d = 0) {

  if (visited[now])
    return false;
  visited[now] = true;

  depth[now] = d;

  for (int i = 0; i < G[now].size(); i++) {
    if (G[now][i].first != back)
      tree[G[now][i].second] = dfs(G[now][i].first, now, d + 1);
  }

  return true;
}

vector<int> cprG[SIZE];

int cprID[SIZE];
int cprSize = 0;

int compress(int now, int back = -1) {
  bool need = false;
  int res = -1;
  vector<int> child;

  for (int i = 0; i < G[now].size(); i++) {
    if (G[now][i].first != back && tree[G[now][i].second]) {
      int p = compress(G[now][i].first, now);

      if (p != -1) {
        child.push_back(p);
      }
    }

    need |= !tree[G[now][i].second];
  }

  need |= back == -1;
  need |= child.size() >= 2;

  if (need) {
    for (int i = 0; i < child.size(); i++) {
      int p = now;
      int q = child[i];
      cprG[p].push_back(q);
      cprG[q].push_back(p);
      cprSize++;
    }
    res = now;

    cprID[now] = cprSize++;
  }

  if (!need && child.size() == 1) {
    res = child[0];
  }

  return res;
}

void cprdfs(int *sum, vector<pair<int, int>> &vec, int now, int back = -1) {

  for (int i = 0; i < cprG[now].size(); i++) {
    if (cprG[now][i] == back)
      continue;

    cprdfs(sum, vec, cprG[now][i], now);

    sum[cprID[now]] += sum[cprID[cprG[now][i]]];

    if (sum[cprID[cprG[now][i]]] % 2) {
      vec.push_back({now, cprG[now][i]});
    }
  }
}

int main() {
  int n, m;

  scanf("%d%d", &n, &m);

  for (int i = 0; i < m; i++) {
    scanf("%d%d", u + i, v + i);
    u[i]--;
    v[i]--;
    G[u[i]].push_back({v[i], i});
    G[v[i]].push_back({u[i], i});
  }

  dfs(0);

  compress(0);

  debug(cprSize);

  pair<int, int> addEdge[17];
  int s = 0;

  for (int i = 0; i < m; i++) {
    if (!tree[i]) {
      if (depth[u[i]] > depth[v[i]])
        swap(u[i], v[i]);
      addEdge[s++] = {u[i], v[i]};
    }
  }

  int ans = 0;
  int sum[SIZE] = {};
  int inedge[SIZE] = {};

  for (int i = 1; i < (1 << s); i++) {
    vector<pair<int, int>> vec;

    for (int i = 0; i < cprSize; i++) {
      sum[i] = inedge[i] = 0;
    }

    for (int j = 0; j < s; j++) {
      if (i & (1 << j)) {
        sum[cprID[addEdge[j].first]]--;
        sum[cprID[addEdge[j].second]]++;
        vec.push_back({addEdge[j].first, addEdge[j].second});
      }
    }

    cprdfs(sum, vec, 0);

    // debug(vec.size());

    bool flag = true;
    UnionFind uf(cprSize);
    int group = 0;

    // 入次数2
    for (int j = 0; j < vec.size(); j++) {
      inedge[cprID[vec[j].first]]++;
      inedge[cprID[vec[j].second]]++;
      group += uf.set(cprID[vec[j].first], cprID[vec[j].second]);
    }

    for (int j = 0; j < vec.size(); j++) {
      flag &= inedge[cprID[vec[j].first]] == 2;
      flag &= inedge[cprID[vec[j].second]] == 2;
    }

    // 連結
    flag &= group == vec.size() - 1;
    ans += flag;
  }

  printf("%d\n", ans);

  return 0;
}


Fixed submission:
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <complex>

#include <cassert>
#include <functional>

typedef long long ll;
using namespace std;

#define debug(x) cerr << #x << " = " << (x) << endl;

#define mod 1000000007              // 1e9+7(prime number)
#define INF 1000000000              // 1e9
#define LLINF 2000000000000000000LL // 2e18
#define SIZE 100020

/* UnionFind */

struct UnionFind {
  vector<int> data, tree_size;
  UnionFind(int s) : data(s, -1), tree_size(s, 1) {}

  int root(int x) {
    if (data[x] == -1)
      return x;
    return data[x] = root(data[x]);
  }

  bool set(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    data[y] = x;
    tree_size[x] += tree_size[y];
    tree_size[y] = 0;
    return true;
  }

  bool check(int x, int y) {
    x = root(x);
    y = root(y);
    return x == y;
  }

  int size(int x) { return tree_size[root(x)]; }
};

vector<pair<int, int>> G[SIZE];
bool tree[SIZE];
int u[SIZE], v[SIZE];
int visited[SIZE];
int depth[SIZE];

bool dfs(int now, int back = -1, int d = 0) {

  if (visited[now])
    return false;
  visited[now] = true;

  depth[now] = d;

  for (int i = 0; i < G[now].size(); i++) {
    if (G[now][i].first != back)
      tree[G[now][i].second] = dfs(G[now][i].first, now, d + 1);
  }

  return true;
}

vector<int> cprG[SIZE];

int cprID[SIZE];
int cprSize = 0;

int compress(int now, int back = -1) {
  bool need = false;
  int res = -1;
  vector<int> child;

  for (int i = 0; i < G[now].size(); i++) {
    if (G[now][i].first != back && tree[G[now][i].second]) {
      int p = compress(G[now][i].first, now);

      if (p != -1) {
        child.push_back(p);
      }
    }

    need |= !tree[G[now][i].second];
  }

  need |= back == -1;
  need |= child.size() >= 2;

  if (need) {
    for (int i = 0; i < child.size(); i++) {
      int p = now;
      int q = child[i];
      cprG[p].push_back(q);
      cprG[q].push_back(p);
      cprSize++;
    }
    res = now;

    cprID[now] = cprSize++;
  }

  if (!need && child.size() == 1) {
    res = child[0];
  }

  return res;
}

void cprdfs(int *sum, vector<pair<int, int>> &vec, int now, int back = -1) {

  for (int i = 0; i < cprG[now].size(); i++) {
    if (cprG[now][i] == back)
      continue;

    cprdfs(sum, vec, cprG[now][i], now);

    sum[cprID[now]] += sum[cprID[cprG[now][i]]];

    if (sum[cprID[cprG[now][i]]] % 2) {
      vec.push_back({now, cprG[now][i]});
    }
  }
}

int main() {
  int n, m;

  scanf("%d%d", &n, &m);

  for (int i = 0; i < m; i++) {
    scanf("%d%d", u + i, v + i);
    u[i]--;
    v[i]--;
    G[u[i]].push_back({v[i], i});
    G[v[i]].push_back({u[i], i});
  }

  dfs(0);

  compress(0);

  // debug(cprSize);

  pair<int, int> addEdge[17];
  int s = 0;

  for (int i = 0; i < m; i++) {
    if (!tree[i]) {
      if (depth[u[i]] > depth[v[i]])
        swap(u[i], v[i]);
      addEdge[s++] = {u[i], v[i]};
    }
  }

  int ans = 0;
  int sum[SIZE] = {};
  int inedge[SIZE] = {};

  for (int i = 1; i < (1 << s); i++) {
    vector<pair<int, int>> vec;

    for (int i = 0; i < cprSize; i++) {
      sum[i] = inedge[i] = 0;
    }

    for (int j = 0; j < s; j++) {
      if (i & (1 << j)) {
        sum[cprID[addEdge[j].first]]--;
        sum[cprID[addEdge[j].second]]++;
        vec.push_back({addEdge[j].first, addEdge[j].second});
      }
    }

    cprdfs(sum, vec, 0);

    // debug(vec.size());

    bool flag = true;
    UnionFind uf(cprSize);
    int group = 0;

    // 入次数2
    for (int j = 0; j < vec.size(); j++) {
      inedge[cprID[vec[j].first]]++;
      inedge[cprID[vec[j].second]]++;
      group += uf.set(cprID[vec[j].first], cprID[vec[j].second]);
    }

    for (int j = 0; j < vec.size(); j++) {
      flag &= inedge[cprID[vec[j].first]] == 2;
      flag &= inedge[cprID[vec[j].second]] == 2;
    }

    // 連結
    flag &= group == vec.size() - 1;
    ans += flag;
  }

  printf("%d\n", ans);

  return 0;
}