Problem p03321 (C++)

Buggy submission (status: Runtime Error):
// #define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; ++i)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
using namespace std;
using ll = int64_t;
using ld = long double;
using P = pair<int, int>;
using vs = vector<string>;
using vi = vector<int>;
using vvi = vector<vi>;
template <class T> using PQ = priority_queue<T>;
template <class T> using PQG = priority_queue<T, vector<T>, greater<T>>;
const int INF = 0xccccccc;
const ll LINF = 922337203685477580LL;
template <typename T1, typename T2> inline bool chmax(T1 &a, T2 b) {
  return a < b && (a = b, true);
}
template <typename T1, typename T2> inline bool chmin(T1 &a, T2 b) {
  return a > b && (a = b, true);
}
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) {
  return is >> p.first >> p.second;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  return os << p.first << ' ' << p.second;
}

struct UnionFind {
  vector<int> par; // 親を指すvector,-par[親]は木のサイズ
  UnionFind(int n) : par(n, -1) {} // uniteで親を埋め込んでいく必要あり
  int root(int x) {                // 親をたどる&データの整理
    if (par[x] < 0)
      return x;
    return par[x] = root(par[x]);
  }
  bool unite(int x, int y) { // データの結合
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (par[x] > par[y])
      swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return true;
  }
  bool same(int x, int y) { return root(x) == root(y); } // 所属判定
  int size(int x) { return -par[root(x)]; }              // 木のサイズ
};

const int N = 710;

// head

int n, m;
bitset<N> dist[N];
UnionFind uft(N << 1);
vi G[N];
vector<P> info;
bitset<N> check;
vi iin;

inline int cc(int n) { return n * (n - 1) >> 1; }

void dfs(int i, bool parity, int ui) {
  if (parity)
    info[ui].first++;
  else
    info[ui].second++;
  for (int ne : G[i])
    if (!check.test(ne)) {
      check.set(ne);
      if (parity)
        dfs(ne, false, ui);
      else
        dfs(ne, true, ui);
    }
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cin >> n >> m;
  rep(i, m) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    dist[a].set(b);
    dist[b].set(a);
  }
  rep(i, n) rep(j, i) if (!dist[i].test(j)) {
    G[i].emplace_back(j);
    G[j].emplace_back(i);
    uft.unite(i, j + n);
    uft.unite(j, i + n);
    if (uft.same(i, i + n) or uft.same(j, j + n)) {
      cout << -1 << endl;
      return 0;
    }
  }
  rep(i, n) if (!check.test(i)) {
    info.emplace_back(0, 0);
    check.set(i);
    dfs(i, true, info.size() - 2);
  }
  rep(i, info.size()) { iin.emplace_back(abs(info[i].first - info[i].second)); }
  m = iin.size();
  vector<bool> dp(n * 2 + 1), dpp(n * 2 + 1);
  vector<bool>::iterator now = dp.begin(), pre = dpp.begin();
  dpp[n] = true;
  rep(i, m) {
    rep(j, n * 2 + 1) {
      now[j] = false;
      if (j >= iin[i] and pre[j - iin[i]])
        now[j] = true;
      if (j <= n * 2 - iin[i] and pre[j + iin[i]])
        now[j] = true;
    }
    swap(now, pre);
  }
  rep(i, n + 1) {
    if (pre[n - i] or pre[n + i]) {
      cout << cc((n - i) >> 1) + cc(n - ((n - i) >> 1)) << endl;
      return 0;
    }
  }
}

Fixed submission:
// #define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; ++i)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
using namespace std;
using ll = int64_t;
using ld = long double;
using P = pair<int, int>;
using vs = vector<string>;
using vi = vector<int>;
using vvi = vector<vi>;
template <class T> using PQ = priority_queue<T>;
template <class T> using PQG = priority_queue<T, vector<T>, greater<T>>;
const int INF = 0xccccccc;
const ll LINF = 922337203685477580LL;
template <typename T1, typename T2> inline bool chmax(T1 &a, T2 b) {
  return a < b && (a = b, true);
}
template <typename T1, typename T2> inline bool chmin(T1 &a, T2 b) {
  return a > b && (a = b, true);
}
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) {
  return is >> p.first >> p.second;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  return os << p.first << ' ' << p.second;
}

struct UnionFind {
  vector<int> par; // 親を指すvector,-par[親]は木のサイズ
  UnionFind(int n) : par(n, -1) {} // uniteで親を埋め込んでいく必要あり
  int root(int x) {                // 親をたどる&データの整理
    if (par[x] < 0)
      return x;
    return par[x] = root(par[x]);
  }
  bool unite(int x, int y) { // データの結合
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (par[x] > par[y])
      swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return true;
  }
  bool same(int x, int y) { return root(x) == root(y); } // 所属判定
  int size(int x) { return -par[root(x)]; }              // 木のサイズ
};

const int N = 710;

// head

int n, m;
bitset<N> dist[N];
UnionFind uft(N << 1);
vi G[N];
vector<P> info;
bitset<N> check;
vi iin;

inline int cc(int n) { return n * (n - 1) >> 1; }

void dfs(int i, bool parity, int ui) {
  if (parity)
    info[ui].first++;
  else
    info[ui].second++;
  for (int ne : G[i])
    if (!check.test(ne)) {
      check.set(ne);
      if (parity)
        dfs(ne, false, ui);
      else
        dfs(ne, true, ui);
    }
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cin >> n >> m;
  rep(i, m) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    dist[a].set(b);
    dist[b].set(a);
  }
  rep(i, n) rep(j, i) if (!dist[i].test(j)) {
    G[i].emplace_back(j);
    G[j].emplace_back(i);
    uft.unite(i, j + n);
    uft.unite(j, i + n);
    if (uft.same(i, i + n) or uft.same(j, j + n)) {
      cout << -1 << endl;
      return 0;
    }
  }
  rep(i, n) if (!check.test(i)) {
    info.emplace_back(0, 0);
    check.set(i);
    dfs(i, true, info.size() - 1);
  }
  rep(i, info.size()) { iin.emplace_back(abs(info[i].first - info[i].second)); }
  m = iin.size();
  vector<bool> dp(n * 2 + 1), dpp(n * 2 + 1);
  vector<bool>::iterator now = dp.begin(), pre = dpp.begin();
  dpp[n] = true;
  rep(i, m) {
    rep(j, n * 2 + 1) {
      now[j] = false;
      if (j >= iin[i] and pre[j - iin[i]])
        now[j] = true;
      if (j <= n * 2 - iin[i] and pre[j + iin[i]])
        now[j] = true;
    }
    swap(now, pre);
  }
  rep(i, n + 1) {
    if (pre[n - i] or pre[n + i]) {
      cout << cc((n - i) >> 1) + cc(n - ((n - i) >> 1)) << endl;
      return 0;
    }
  }
}