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

#include <bits/stdc++.h>

#define set unordered_set
#define map unordered_map

using namespace std;

class UnionFind {
private:
  int size;
  int parent[40000];
  int rank[40000];

public:
  UnionFind() {}
  UnionFind(int sz) { init(sz); }
  void init(int sz) {
    size = sz;
    fill(rank, rank + sz, 0);
    for (int i = 0; i < sz; ++i) {
      parent[i] = i;
    }
  }
  int root(int n) {
    if (parent[n] == n)
      return n;
    return parent[n] = root(parent[n]);
  }
  void unite(int n, int m) {
    int x = root(n);
    int y = root(m);
    if (x == y)
      return;

    if (rank[x] < rank[y]) {
      parent[x] = y;
    } else if (rank[x] > rank[y]) {
      parent[y] = x;
    } else {
      parent[x] = y;
      ++rank[y];
    }
  }
  bool isUnited(int n, int m) { return root(n) == root(m); }
};

struct Query {
  int type, u, v;
};

typedef vector<map<int, int>> Graph;

const int bucket = 50;

map<int, int> make_table(set<int> &use) {
  map<int, int> res;
  int n = 0;
  for (set<int>::iterator it = use.begin(); it != use.end(); ++it, ++n) {
    res[*it] = n;
  }
  return res;
}
Graph trim(Graph &G, set<int> &use, map<int, int> &tbl) {
  tbl = make_table(use);

  int i = 0;
  Graph res(use.size());
  UnionFind uf(G.size());
  for (int i = 0; i < G.size(); ++i) {
    for (map<int, int>::iterator it = G[i].begin(); it != G[i].end(); ++it) {
      if (it->second) {
        int v = it->first;
        if (!use.count(i) || !use.count(v)) {
          uf.unite(i, v);
        }
      }
    }
  }
  for (set<int>::iterator it1 = use.begin(); it1 != use.end(); ++it1) {
    for (set<int>::iterator it2 = use.begin(); it2 != use.end(); ++it2) {
      if (uf.isUnited(*it1, *it2)) {
        tbl[*it1] = tbl[*it2];
      }
    }
  }
  for (set<int>::iterator it1 = use.begin(); it1 != use.end(); ++it1) {
    for (set<int>::iterator it2 = use.begin(); it2 != use.end(); ++it2) {
      if (G[*it1].find(*it2) != G[*it1].end() && G[*it1].find(*it2)->second) {
        res[tbl[*it1]][tbl[*it2]]++;
      }
    }
  }
  return res;
}
void unite(Graph &G, int u, int v) {
  G[u][v]++;
  G[v][u]++;
}
void remove(Graph &G, int u, int v) {
  //	--G[u][v];
  //	--G[v][u];
  if (--G[u][v] == 0)
    G[u].erase(v);
  if (--G[v][u] == 0)
    G[v].erase(u);
}
bool judge(Graph &G, int v, int t, vector<bool> &reached) {
  if (v == t)
    return true;
  reached[v] = true;
  for (map<int, int>::iterator it = G[v].begin(); it != G[v].end(); ++it) {
    int to = it->first;
    if (!reached[to]) {
      if (judge(G, to, t, reached))
        return true;
    }
  }
  return false;
}
bool judge(Graph &G, int s, int t) {
  vector<bool> reached(G.size(), false);
  return judge(G, s, t, reached);
}
/*
bool judge(Graph& G, int s, int t) {
        assert(G.size() <= bucket*2);
        bool reached[bucket*2] = {0};
        queue<int> Q; Q.push(s); reached[s] = true;
        while ( !Q.empty() ) {
                int v = Q.front(); Q.pop();
                for (map<int, int>::iterator it = G[v].begin(); it !=
G[v].end(); ++it) { int to = it->first; if ( !reached[to] ) { reached[to] =
true; Q.push(to);
                        }
                }
        }
        return reached[t];
}
*/

int main() {
  int N, M;
  cin >> N >> M;
  Query Q[40000];
  for (int i = 0; i < M; ++i) {
    int t, u, v;
    scanf("%d%d%d", &t, &u, &v);
    Q[i] = (Query){t, u, v};
  }
  set<int> use[40000 / bucket + 1];
  for (int i = 0; i < M; ++i) {
    int type = Q[i].type, u = Q[i].u, v = Q[i].v;
    use[i / bucket].insert(u);
    use[i / bucket].insert(v);
  }
  Graph G(N);
  Graph g;
  map<int, int> tbl;
  for (int i = 0; i < M; ++i) {
    int type = Q[i].type, u = Q[i].u, v = Q[i].v;
    if (i % bucket == 0) {
      g = trim(G, use[i / bucket], tbl);
    }
    switch (type) {
    case 1: // unite
      unite(G, u, v);
      unite(g, tbl[u], tbl[v]);
      break;
    case 2: // remove
      remove(G, u, v);
      remove(g, tbl[u], tbl[v]);
      break;
    case 3: // judge
      if (judge(g, tbl[u], tbl[v])) {
        cout << "YES" << endl;
      } else {
        cout << "NO" << endl;
      }
      break;
    }
  }
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>

using namespace std;

class UnionFind {
private:
  int size;
  int parent[40000];
  int rank[40000];

public:
  UnionFind() {}
  UnionFind(int sz) { init(sz); }
  void init(int sz) {
    size = sz;
    fill(rank, rank + sz, 0);
    for (int i = 0; i < sz; ++i) {
      parent[i] = i;
    }
  }
  int root(int n) {
    if (parent[n] == n)
      return n;
    return parent[n] = root(parent[n]);
  }
  void unite(int n, int m) {
    int x = root(n);
    int y = root(m);
    if (x == y)
      return;

    if (rank[x] < rank[y]) {
      parent[x] = y;
    } else if (rank[x] > rank[y]) {
      parent[y] = x;
    } else {
      parent[x] = y;
      ++rank[y];
    }
  }
  bool isUnited(int n, int m) { return root(n) == root(m); }
};

struct Query {
  int type, u, v;
};

typedef vector<map<int, int>> Graph;

const int bucket = 50;

map<int, int> make_table(set<int> &use) {
  map<int, int> res;
  int n = 0;
  for (set<int>::iterator it = use.begin(); it != use.end(); ++it, ++n) {
    res[*it] = n;
  }
  return res;
}
Graph trim(Graph &G, set<int> &use) {
  int i = 0;
  Graph res(use.size());
  UnionFind uf(G.size());
  for (int i = 0; i < G.size(); ++i) {
    for (map<int, int>::iterator it = G[i].begin(); it != G[i].end(); ++it) {
      if (it->second) {
        int v = it->first;
        if (!use.count(i) || !use.count(v)) {
          uf.unite(i, v);
        }
      }
    }
  }
  for (set<int>::iterator it1 = use.begin(); it1 != use.end(); ++it1, ++i) {
    int j = 0;
    for (set<int>::iterator it2 = use.begin(); it2 != use.end(); ++it2, ++j) {
      if (uf.isUnited(*it1, *it2)) {
        res[i][j]++;
      }
      if (G[*it1].find(*it2) != G[*it1].end() && G[*it1].find(*it2)->second) {
        res[i][j]++;
      }
    }
  }
  return res;
}
void unite(Graph &G, int u, int v) {
  G[u][v]++;
  G[v][u]++;
}
void remove(Graph &G, int u, int v) {
  //	--G[u][v];
  //	--G[v][u];
  if (--G[u][v] == 0)
    G[u].erase(v);
  if (--G[v][u] == 0)
    G[v].erase(u);
}
bool judge(Graph &G, int v, int t, vector<bool> &reached) {
  if (v == t)
    return true;
  reached[v] = true;
  for (map<int, int>::iterator it = G[v].begin(); it != G[v].end(); ++it) {
    int to = it->first;
    if (!reached[to]) {
      if (judge(G, to, t, reached))
        return true;
    }
  }
  return false;
}
bool judge(Graph &G, int s, int t) {
  vector<bool> reached(G.size(), false);
  return judge(G, s, t, reached);
}
/*
bool judge(Graph& G, int s, int t) {
        assert(G.size() <= bucket*2);
        bool reached[bucket*2] = {0};
        queue<int> Q; Q.push(s); reached[s] = true;
        while ( !Q.empty() ) {
                int v = Q.front(); Q.pop();
                for (map<int, int>::iterator it = G[v].begin(); it !=
G[v].end(); ++it) { int to = it->first; if ( !reached[to] ) { reached[to] =
true; Q.push(to);
                        }
                }
        }
        return reached[t];
}
*/

int main() {
  int N, M;
  cin >> N >> M;
  Query Q[40000];
  for (int i = 0; i < M; ++i) {
    int t, u, v;
    scanf("%d%d%d", &t, &u, &v);
    Q[i] = (Query){t, u, v};
  }
  set<int> use[40000 / bucket + 1];
  for (int i = 0; i < M; ++i) {
    int type = Q[i].type, u = Q[i].u, v = Q[i].v;
    use[i / bucket].insert(u);
    use[i / bucket].insert(v);
  }
  Graph G(N);
  Graph g;
  map<int, int> tbl;
  for (int i = 0; i < M; ++i) {
    int type = Q[i].type, u = Q[i].u, v = Q[i].v;
    if (i % bucket == 0) {
      tbl = make_table(use[i / bucket]);
      g = trim(G, use[i / bucket]);
    }
    switch (type) {
    case 1: // unite
      unite(G, u, v);
      unite(g, tbl[u], tbl[v]);
      break;
    case 2: // remove
      remove(G, u, v);
      remove(g, tbl[u], tbl[v]);
      break;
    case 3: // judge
      if (judge(g, tbl[u], tbl[v])) {
        cout << "YES" << endl;
      } else {
        cout << "NO" << endl;
      }
      break;
    }
  }
}