Problem p00817 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int INF = 1000000000;
#define REP(i, s, n) for (int i = (int)(s); i < (int)(n); i++)
#define rep(i, n) REP(i, 0, n)
struct UnionFind {
  vector<int> data;
  UnionFind() {}
  UnionFind(int N) : data(N, -1) {}
  void unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      data[x] += data[y];
      data[y] = x;
    }
  }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  bool same(int a, int b) { return root(a) == root(b); }
};
int L[601], R[601];

int dp[601][301], from[601][301];
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int N, p1, p2;
  while (cin >> N >> p1 >> p2 && (N || p1 || p2)) {
    int P = p1 + p2;
    int x_, y_;
    string a_;
    UnionFind uf(P * 2); // node_i := if i % 2 (i / 2) is F else (i / 2) is T
    rep(i, N) {
      cin >> x_ >> y_ >> a_;
      --x_;
      --y_;
      if (a_ == "yes")
        uf.unite(x_ * 2, y_ * 2), uf.unite(x_ * 2 + 1, y_ * 2 + 1);
      else
        uf.unite(x_ * 2, y_ * 2 + 1), uf.unite(x_ * 2 + 1, y_ * 2);
    }
    memset(L, 0, sizeof(L));
    memset(R, 0, sizeof(R));
    rep(i, P) {
      int par = uf.root(i * 2);
      if (par % 2)
        R[par / 2]++;
      else
        L[par / 2]++;
    }
    memset(dp, 0, sizeof(dp));
    memset(from, 0, sizeof(from));
    int it = 0;
    dp[0][0] = 1;
    auto upd = [](int &a, int b) {
      if (b == 0)
        return false;
      a = min(2, a + b);
      return true;
    };
    vector<int> group(P, 0);
    int curj;
    vector<bool> useR(P, false);
    rep(i, P) {
      if (L[i] == 0 && R[i] == 0)
        continue;
      if (L[i] == R[i])
        goto fail;
      ++it;
      group[it] = i;
      rep(j, p1 + 1) {
        if (upd(dp[it][j + L[i]], dp[it - 1][j]))
          from[it][j + L[i]] = j;
        if (upd(dp[it][j + R[i]], dp[it - 1][j]))
          from[it][j + R[i]] = j;
      }
    }
    if (dp[it][p1] != 1)
      goto fail;
    curj = p1;
    for (int i = it; i >= 1; --i) {
      int temp = curj - from[i][curj];
      if (temp == R[group[i]])
        useR[group[i]] = true;
      curj -= temp;
    }
    rep(i, P) {
      int par = uf.root(i * 2);
      if ((par % 2 && useR[par / 2]) || (par % 2 == 0 && !useR[par / 2]))
        cout << i + 1 << endl;
    }
    cout << "end" << endl;
    continue;
  fail:
    cout << "no" << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int INF = 1000000000;
#define REP(i, s, n) for (int i = (int)(s); i < (int)(n); i++)
#define rep(i, n) REP(i, 0, n)
struct UnionFind {
  vector<int> data;
  UnionFind() {}
  UnionFind(int N) : data(N, -1) {}
  void unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      data[x] += data[y];
      data[y] = x;
    }
  }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  bool same(int a, int b) { return root(a) == root(b); }
};
typedef pair<int, int> pint;
int N, p1, p2, P, T, F;
vector<pint> contra;
int group[301];
UnionFind ans;
bool captured(int par) { return par == T || par == F; }
bool dfs(UnionFind uf, int it, int Tnum, int Fnum) {
  if (it == contra.size()) {
    //        cout << Tnum << ' ' << Fnum << endl;
    if (pint(p1, p2) == pint(Tnum, Fnum)) {
      ans = uf;
      return true;
    } else if (pint(p1, p2) == pint(Fnum, Tnum)) {
      swap(T, F);
      ans = uf;
      return true;
    }
    return false;
  }
  int par1 = uf.root(contra[it].first), par2 = uf.root(contra[it].second);
  if (par1 == par2)
    return false;
  bool cap1 = captured(par1), cap2 = captured(par2);
  if (cap1 && cap2)
    return dfs(uf, it + 1, Tnum, Fnum);
  if (cap1) {
    int opo = par1 == T ? F : T;
    if (par1 == T)
      Fnum += group[par2];
    else
      Tnum += group[par2];
    uf.unite(opo, par2);
    return dfs(uf, it + 1, Tnum, Fnum);
  }
  if (cap2) {
    int opo = par2 == T ? F : T;
    if (par2 == T)
      Fnum += group[par1];
    else
      Tnum += group[par1];
    uf.unite(opo, par1);
    return dfs(uf, it + 1, Tnum, Fnum);
  }
  UnionFind temp = uf;
  temp.unite(T, par1);
  temp.unite(F, par2);
  if (dfs(temp, it + 1, Tnum + group[par1], Fnum + group[par2]))
    return true;
  uf.unite(F, par1);
  uf.unite(T, par2);
  return dfs(uf, it + 1, Tnum + group[par2], Fnum + group[par1]);
}
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  while (cin >> N >> p1 >> p2 && (N || p1 || p2)) {
    P = p1 + p2;
    T = P;
    F = T + 1;
    UnionFind uf(P + 2);
    int x_, y_;
    string a_;
    contra.clear();
    rep(i, N) {
      cin >> x_ >> y_ >> a_;
      --x_;
      --y_;
      if (a_ == "yes")
        uf.unite(x_, y_);
      else
        contra.push_back(pint(x_, y_));
    }
    if (p1 == p2)
      goto fail;
    if (p1 == 0 || p2 == 0) {
      if (p1)
        rep(i, P) cout << i + 1 << endl;
      cout << "end" << endl;
    }
    memset(group, 0, sizeof(group));
    rep(i, P) group[uf.root(i)]++;
    if (dfs(uf, 0, 0, 0)) {
      rep(i, P) if (ans.root(i) == T) cout << i + 1 << endl;
      cout << "end" << endl;
      continue;
    }
  fail:
    cout << "no" << endl;
  }
  return 0;
}