Problem:
Problem D: Graph Construction

n 匹のうさぎがいて, 0 番からn − 1 番の番号がついた小屋に1 匹ずつ住んでいる.

あるとき, 秘密の組織によって地下通路の建設工事が行われる, という情報がうさぎたちのもとへ入った. 地下通路を使えば, うさぎたちは他のうさぎたちの小屋へ遊びに行けるようになって嬉しい.

通路は両方向に進むことができ, また通路同士は交わらない. 諸事情により, 一度建設された通路が破壊されてしまうこともある. 通路の建設や破壊の工事は1 本ずつ行われ, 各工事中はうさぎは自分の小屋に留まっているものとする.

うさぎたちは, 工事のいくつかの段階において, あるうさぎとあるうさぎが遊べるかどうかを事前に知りたい. うさぎたちは仲良しなので, 遊びに行くときに他のうさぎの小屋を自由に通ることができる. プログラミングが好きなうさぎたちは, 昔似たような問題を解いたので簡単だろうと思って挑戦し出したが, なかなか効率の良いプログラムが書けない. うさぎの代わりにこの問題を解け.

Input

入力の一行目にはn とk がスペース区切りで与えられる。2 ≤ n ≤ 40 000, 1 ≤ k ≤ 40 000

つづくk 行には工事情報と質問が合わせて, 時間順に与えられる.

“1 u v” — 小屋u とv を結ぶ通路が建設される. 小屋u とv を結ぶ通路がないときにのみ現れる.

“2 u v” — 小屋u とv を結ぶ通路が破壊される. 小屋u とv を結ぶ通路があるときにのみ現れる.

“3 u v” — 小屋u とv のうさぎが遊べるかどうか判定せよ.

0 ≤ u < v < n

Output

入力に現れる各質問について, 遊べるなら”YES”を, そうでないなら”NO”を1 行ずつ出力せよ.

Sample Input 1

4 10
1 0 1
1 0 2
3 1 2
2 0 1
1 2 3
3 0 1
1 0 1
2 0 2
1 1 3
3 0 2

Sample Output 1

YES
NO
YES

Solution in C++ (judge verdict: Wrong Answer)

#include<bits/stdc++.h>
using namespace std;
const int INF = 1 << 30;
 
template<typename T1, typename T2> istream& operator>>(istream& is, pair<T1,T2>& a){ return is >> a.first >> a.second; }
template<typename T1, typename T2> ostream& operator<<(ostream& os, pair<T1,T2>& a){ return os << a.first << " "<<a.second; }
template<typename T> istream& operator>>(istream& is, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) is >> vc[i]; return is; }
template<typename T> ostream& operator<<(ostream& os, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) os << vc[i] << endl; return os; }
  
#define ForEach(it,c) for(__typeof (c).begin() it = (c).begin(); it != (c).end(); it++)
#define ALL(v) (v).begin(), (v).end()
#define UNQ(s) { sort(ALL(s)); (s).erase( unique( ALL(s)), (s).end());}
#define fr first
#define sc second
  
typedef pair< int , int > Pi;
typedef pair< bool, Pi > Pii;
  
typedef long long int64;
 
Pii loger[40000];
int sz = 0;

class UnionFind{
private:
  vector< int > rank, p;
 
  void link(int x,int y){
    if(rank[x] > rank[y]){
      p[y] = x;
    } else {
      p[x] = y;
      if(rank[x] == rank[y]) rank[y]++;
    }
  }
public:
  UnionFind(){};
  void init(int size){
    rank.assign( size, 0);
    p.assign( size, 0);
    for(int i = 0; i < size; i++) p[i] = i, rank[i] = 0;
  }
 
  void Union(int x,int y, bool flag = false){
    if(Find(x) != Find(y)){
      if(flag) loger[sz++] =  Pii( rank[x] == rank[y], Pi(x, y));
      link(Find(x),Find(y));
    }
  }
  int Find(int x){
    return( x != p[x] ? p[x] = Find(p[x]) : p[x]);
  }
  void BackUp(){
    while(sz > 0){
      Pii& top = loger[--sz];
      p[top.second.first] = top.second.first;
      p[top.second.second] = top.second.second;
      if(top.first) rank[top.second.second]--;
    }
  }
};
const int SQR = 150;
set< Pi > T; // 変化があった辺
set< Pi > S; // 存在する辺
 
int main(){
  int n, Q;
  int x[40000], y[40000], z[40000];
 
  scanf("%d %d", &n, &Q);
  UnionFind uf;
  for(int i = 0; i < Q; i++){
    scanf("%d %d %d", &x[i], &y[i], &z[i]);
  }
  for(int i = 0; i < Q; i++){
    if(i % SQR == 0){
      int begin = i, end = min( i + SQR, Q);
      T.clear(); uf.init(n);
      for(int j = begin; j < end; j++){
        if(x[j] != 3){
          T.insert( make_pair( y[j], z[j]));
          if(x[j] == 1) S.insert( make_pair( y[j], z[j]));
          else if(x[j] == 2) S.erase( make_pair( y[j], z[j]));
        }
      }
      ForEach( it, S){
        if(T.find(*it) == T.end()){ // 以前に追加されていて変化がない辺を結合
          uf.Union( it -> first, it -> second);
        }
      }
    }
    if(x[i] == 3){
      set< Pi > u;
      int N = i / SQR * SQR;
      for(int k = 0; k < i % SQR; k++){ // それ以前
        if(x[k + N] == 1) u.insert( make_pair( y[N + k], z[N + k]));
        else if(x[k + N] == 2) u.erase( make_pair( y[N + k], z[N + k]));
      }
      for(int k = min( SQR - 1, Q - N - 1); k > i % SQR; k--){ // それ以後
        if(x[k + N] == 1) u.erase( make_pair( y[N + k], z[N + k]));
        else if(x[k + N] == 2) u.insert( make_pair( y[N + k], z[N + k]));    
      }
      ForEach( it, u){
        uf.Union( it -> first, it -> second, true);
      }
      puts(uf.Find(y[i]) == uf.Find(z[i]) ? "YES" : "NO");
      uf.BackUp();
    }
  }
}