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++11 (judge verdict: Time Limit Exceeded)

#include <bits/stdc++.h>
using namespace std;

#define for_(i,a,b) for(int i=(a);i<(b);++i)
#define allof(a) (a).begin(),(a).end()
typedef pair< int, int > pii;

struct Edge : pii {
	Edge(int u, int v) : pii(u, v) {}
	int u() { return first; }
	int v() { return second; }
};

class UnionFind {
private:
	vector< int > data;
	int num_of_g;
	
public:
	UnionFind(int n) : data(n, -1), num_of_g(n) {}
	
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		
		if (x == y) return 0;
		
		if (data[y] < data[x]) swap(x, y);
		data[x] += data[y]; data[y] = x;
		--num_of_g;
		
		return 1;
	}
	
	bool sameSet(int x, int y) { return root(x) == root(y); }
	int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
	int size(int x) { return -data[root(x)]; }
	int getNumOfG() { return num_of_g; }
};

#define BUCKET_SIZE 200
int n, k, id[40010], t[40010], u[40010], v[40010];
vector< multiset< int > > eset;
vector< bool > vis;

bool dfs(int v, int tar) {
	if (v == tar) return true;
	if (vis[v]) return false;
	
	vis[v] = true;
	
	for (int u : eset[v]) if (dfs(u, tar)) return true;
	
	return false;
}

void solve() {
	set< Edge > edges;
	
	for (int i = 0; i < k; i += BUCKET_SIZE) {
		// vertex setting
		vector< int > vset;
		
		for (int rep = 0; i + rep < k && rep < BUCKET_SIZE; ++rep) {
			int q = i + rep;
			vset.push_back(u[q]);
			vset.push_back(v[q]);
		}
		
		sort(allof(vset));
		vset.erase(unique(allof(vset)), vset.end());
		
		// graph construction
		int V = vset.size();
		
		for_(i,0,n) id[i] = -1;
		for_(i,0,V) id[vset[i]] = i;
		
		eset.assign(V, multiset< int >());
		
		UnionFind uf(n);
		
		for (Edge e : edges) {
			if (id[e.u()] != -1 && id[e.v()] != -1) {
				eset[id[e.u()]].insert(id[e.v()]);
				eset[id[e.v()]].insert(id[e.u()]);
			} else {
				uf.unionSet(e.u(), e.v());
			}
		}
		
		for_(i,0,V) for_(j,0,V) {
			int u = vset[i], v = vset[j];
			
			if (uf.sameSet(u, v)) {
				eset[i].insert(j);
				eset[j].insert(i);
			}
		}
				
		// query
		for (int rep = 0; i + rep < k && rep < BUCKET_SIZE; ++rep) {
			int q = i + rep;
			
			if (t[q] == 1) {
				eset[id[u[q]]].insert(id[v[q]]);
				eset[id[v[q]]].insert(id[u[q]]);
				edges.insert(Edge(u[q], v[q]));
			}
			
			if (t[q] == 2) {
				eset[id[u[q]]].erase(id[v[q]]);
				eset[id[v[q]]].erase(id[u[q]]);
				edges.erase(Edge(u[q], v[q]));
			}
			
			if (t[q] == 3) {
				vis.assign(V, false);
				cout << (dfs(id[u[q]], id[v[q]]) ? "YES" : "NO") << endl;
			}
		}
	}
}

int main() {
	cin >> n >> k;
	for_(i,0,k) cin >> t[i] >> u[i] >> v[i];
	solve();
}