Go: package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
)

// Node 頂点
type Node struct {
	gid  int   // グループID
	edge []int // 隣接辺
}

// NoID グループIDなし
const NoID = -1

// NewNode 頂点の生成
func NewNode() *Node {
	return &Node{gid: NoID, edge: []int{}}
}

func parseNode(nodes []*Node, gid int, queue []int) {
	if len(queue) == 0 {
		return
	}
	var nextQ []int
	for _, id := range queue {
		node := nodes[id]
		if node.gid == NoID {
			node.gid = gid
			for _, edge := range node.edge {
				nextQ = append(nextQ, edge)
			}
		}
	}
	parseNode(nodes, gid, nextQ)
	return
}
func digNode(nodes []*Node, id, gid int) {
	node := nodes[id]
	if node.gid != NoID {
		// 探索済み
		return
	}
	node.gid = gid
	for _, edge := range node.edge {
		digNode(nodes, edge, gid)
	}
	return
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	n, m := eGetInt2(scanner)

	nodes := make([]*Node, n)
	for i := 0; i < n; i++ {
		nodes[i] = NewNode()
	}

	for i := 0; i < m; i++ {
		a, b := eGetInt2(scanner)
		nodes[a].edge = append(nodes[a].edge, b)
		nodes[b].edge = append(nodes[b].edge, a)
	}

	for i := 0; i < n; i++ {
		// 幅優先探索
		// gid := i
		// queue := []int{i}
		// parseNode(nodes, gid, queue)

		// 深さ優先探索
		digNode(nodes, i, i)
	}

	q := eGetInt(scanner)
	for i := 0; i < q; i++ {
		a, b := eGetInt2(scanner)
		if nodes[a].gid == nodes[b].gid {
			fmt.Println("yes")
		} else {
			fmt.Println("no")
		}
	}
}

func eGetInt(scanner *bufio.Scanner) int {
	t := eAtoi(strings.Fields(eGetline(scanner)))
	return t[0]
}
func eGetInt2(scanner *bufio.Scanner) (int, int) {
	t := eAtoi(strings.Fields(eGetline(scanner)))
	return t[0], t[1]
}

func eGetline(p *bufio.Scanner) string {
	if !p.Scan() {
		if err := p.Err(); err != nil {
			log.Fatal(err.Error())
		}
		return ""
	}
	return p.Text()
}

func eAtoi(s []string) []int {
	ints := make([]int, len(s))
	var err error
	for i, e := range s {
		ints[i], err = strconv.Atoi(e)
		if err != nil {
			log.Fatal(err.Error())
		}
	}
	return ints
}

C++: 


/**
 *      purpose : 
 *      author  : kyomukyomupurin
 *      created : 
**/

// input/output
#include <iostream>
#include <fstream>
#include <sstream>
// container class
#include <array>
#include <deque>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// math, algorithm
#include <algorithm>
#include <cmath>
#include <complex>
#include <numeric>
// etc
#include <bitset>
#include <cassert>
#include <cctype>
#include <cstring>
#include <chrono>
#include <iomanip>
#include <random>
#include <utility>
// using-directive
using namespace std;
// alias template
using int64 = long long;
using vi = vector<int>;
using vl = vector<int64>;
using pii = pair<int, int>;
using pll = pair<int64, int64>;
// text macro replacement
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define print(x) cout << (x) << '\n'
#define debug(x) cerr << #x << ": " << (x) << '\n'
#define dbg(v) for (size_t _ = 0; _ < v.size(); ++_){cerr << #v << "[" << _ << "] : " << v[_] << '\n';}
// variadic template
template<typename T> inline void chmin(T &a, T b) {if (a > b) a = b; return;}
template<typename T> inline void chmax(T &a, T b) {if (a < b) a = b; return;}
// constant
const int INF = (1<<30) - 1;
const int64 INF64 = (1LL<<62) - 1;
const int MOD = 1000000007;



struct UnionFind {
  std::vector<int> par, rank;

  UnionFind(int n) : par(n , -1), rank(n, 0) {}

  void init(int n) {
    par.assign(n, -1); rank.assign(n, 0);
  }

  int root(int x) {
    if (par[x] == -1) return x;
    else return par[x] = root(par[x]);
  }

  bool issame(int x, int y) {return root(x) == root(y);}

  void unite(int x, int y) {
    x = root(x); y = root(y);
    if (x == y) return;
    if (rank[x] < rank[y]) std::swap(x, y);
    if (rank[x] == rank[y]) ++rank[x];
    par[y] = x;
    return;
  }
};


int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);

  int n, m; cin >> n >> m;
  UnionFind uf(n);

  for (int i = 0; i < m; ++i) {
    int x, y; cin >> x >> y;
    if (!uf.issame(x, y)){
      uf.unite(x, y);
    }
  }

  int query; cin >> query;

  for (int i = 0; i < query; ++i) {
    int z, w; cin >> z >> w;
    if (uf.issame(z, w)) {
      cout << "yes" << '\n';
    } else {
      cout << "no" << '\n';
    }
  }

  return 0;
}

C++: #include <stdio.h>
#include <iostream>
#include <queue>
using namespace std;

#define NODE_NUM 100000

queue<int> que;

class Node
{
private:
	int next_num;
	int next_node_list[NODE_NUM];
public:
	Node();
	void AddNextNode(int id);
	bool Search(int st, int ed);
	bool check[NODE_NUM];
	bool link[NODE_NUM];
};

Node::Node()
{
	next_num = 0;
	for (int i = 0; i < NODE_NUM; i++) {
		check[i] = false;
	}
	for (int i = 0; i < NODE_NUM; i++) {
		link[i] = false;
	}
}

void Node::AddNextNode(int id)
{
	next_node_list[next_num] = id;
	next_num++;
}

Node *Node_list;

bool Node::Search(int st, int ed)
{
	if (link[ed]) return true;

	for (int k = 0; k < next_num; k++) {
		Node_list[st].link[next_node_list[k]] = true;
	}

	for (int i = 0; i < next_num; i++) {
		if (next_node_list[i] == ed) return true;
	}
	
	for (int j = 0; j < next_num; j++) {
		if (Node_list[next_node_list[j]].check[ed] == 0) {
			Node_list[next_node_list[j]].check[ed] = 1;
			que.push(next_node_list[j]);
		}
	}
	
	return false;
}

int main(void)
{
	//input
	int n;
	cin >> n;
	Node_list = new Node[n]();
	int m;
	cin >> m;
	for (int i = 0; i < m; i++) {
		int s, t;
		cin >> s >> t;
		Node_list[s].AddNextNode(t);
		Node_list[t].AddNextNode(s);
	}
	
	//output
	int q;
	cin >> q;
	for (int i = 0; i < q; i++) {
		int s, t;
		cin >> s >> t;
		bool ret = Node_list[s].Search(s, t);
		while (!ret && !que.empty()) {
			ret = Node_list[que.front()].Search(s, t);
			que.pop();
		};
		while (!que.empty()) {
			que.pop();
		}

		if (ret) {
			cout << "yes" << "\n";
		}
		else {
			cout << "no" << "\n";
		}
	}
	
	return 0;
}

C++: #include <iostream>
#include <vector>

using namespace std;

class UnionFind
{
public:
	vector<int> par;
	vector<int> rk;
	UnionFind(int n)
	{
		par.resize(n);
		rk.resize(n);
		for (int i = 0; i < n; ++i)
		{
			par[i] = i;
		}
	}
	int find(int x)
	{
		if (par[x] == x)
		{
			return(x);
		}
		return(par[x] = find(par[x]));
	}
	void unite(int x, int y)
	{
		x = find(x);
		y = find(y);
		if (rk[x] < rk[y])
		{
			par[x] = y;
		}
		else
		{
			par[y] = x;
			if (rk[x] == rk[y])
			{
				++rk[x];
			}
		}
	}
	bool same(int x, int y)
	{
		return(find(x) == find(y));
	}
};


void solve()
{
	int n, m;
	cin >> n >> m;
	UnionFind uf(n);
	for (int i = 0; i < m; ++i)
	{
		int s, t;
		cin >> s >> t;
		uf.unite(s, t);
	}
	int q;
	cin >> q;
	for (int i = 0; i < q; ++i)
	{
		int s, t;
		cin >> s >> t;
		if (uf.same(s, t))
		{
			cout << "yes" << endl;
		}
		else
		{
			cout << "no" << endl;
		}
	}
}

int main()
{
	solve();
	return(0);
}