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++: #include <iostream>
#include <stdint.h>
#include <vector>

using namespace std;

#define GRAPH_MAX_SIZE 100000
#define WHITE -1

vector<uint32_t> vertexes[GRAPH_MAX_SIZE];
int32_t colors[GRAPH_MAX_SIZE];

void graph_connected_components_init()
{
  uint32_t i;
  for (i = 0; i < GRAPH_MAX_SIZE; i++) {
    vertexes[i].clear();
    colors[i] = WHITE;
  }
}

void graph_connected_components_add(uint32_t vertex, uint32_t connect_to)
{
  vertexes[vertex].push_back(connect_to);
  vertexes[connect_to].push_back(vertex);
}

uint32_t *graph_connected_components_connected_vertexes(uint32_t vertex)
{
  return &vertexes[vertex][0];
}

void colorize_connecting_vertex(vector<uint32_t> *connect_to, int32_t color)
{
  uint32_t i;
  for (i = 0; i < connect_to->size(); i++) {
    uint32_t index = (*connect_to)[i];
    if (colors[index] == WHITE) {
      colors[index] = color;
      colorize_connecting_vertex(&vertexes[index], color);
    }
  }
}

void graph_connected_components_colorize()
{
  int32_t i;
  for (i = 0; i < 20; i++) {
    if (colors[i] == WHITE) {
      colors[i] = i;
      vector<uint32_t> connect_to = vertexes[i];
      colorize_connecting_vertex(&connect_to, i);
    }
  }
}

bool graph_connected_components_is_connected(uint32_t index1, uint32_t index2)
{
  if (colors[index1] == colors[index2]) return true;
  return false;
}

#if !defined(TEST)
#include <iostream>
using namespace std;
int32_t main(void)
{
  graph_connected_components_init();

  int32_t users, connections;
  cin >> users >> connections;

  uint32_t i;
  for (i = 0; i < connections; i++) {
    uint32_t index, connection;
    cin >> index >> connection;
    graph_connected_components_add(index, connection);
  }
  graph_connected_components_colorize();

  int32_t questions;
  cin >> questions;
  for (i = 0; i < questions; i++) {
    uint32_t index1, index2;
    cin >> index1 >> index2;
    if (graph_connected_components_is_connected(index1, index2)) {
      cout << "yes" << endl;
    } else {
      cout << "no" << endl;
    }
  }

  return 0;
}
#endif

C++: #include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
#define int ll

int rabel[100010], now_rabel;
bool is_search[100010];
vector<int> s, t;

void dfs(int p) {
  //cout << "now p = " << p << endl;
  //cout << "rabel[" << p << "] = " << now_rabel << endl;
  is_search[p] = true;
  rabel[p] = now_rabel;

  for (int i = 0; i < s.size(); i++) {
    if (s[i] > p) break;
    if (s[i] == p && is_search[t[i]] == false) {
      //cout << s[i] << " " << t[i] << endl;
      dfs(t[i]);
    }
  }
  //cout << "end p = " << p << endl;
}

signed main(void) {
  int n, m, o, p, q;

  cin >> n >> m;

  for (int i = 0; i < m; i++) {
    cin >> o >> p;
    s.push_back(o);
    t.push_back(p);
  }

  int k = 0, i;

  while(1) {
    dfs(k);

    for (i = 0; i < n; i++) {
      if (is_search[i] == false) {
        k = i;
        break;
      }
    }
    if(i == n) break;
    now_rabel = k;
    //cout << "rabel changed\n";
  }

  /*for (int i = 0; i < n; i++) {
    cout << i << " " << rabel[i] << endl;
  }*/

  cin >> q;

  for (int i = 0; i < q; i++) {
    cin >> o >> p;
    if(rabel[o] == rabel[p]) {
      cout << "yes\n";
    } else {
      cout << "no\n";
    }
  }
  return 0;
}

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


using ui32 = std::uint32_t;

class union_find {
public:
	using size_type = decltype(std::declval<std::vector<int>>().size());
private:
	std::vector<size_type> par;
	std::vector<size_type> size_;

public:
	union_find() :par{}, size_{} {}
	union_find(size_type s) :union_find{} {
		par.resize(s);
		std::iota(std::begin(par), std::end(par), 0);

		size_.resize(s, 1);
	}

	auto root(size_type index_)->size_type {
		if (par[index_] == index_)
			return
				par[index_];
		else
			return
				par[index_] = root(par[index_]);
	}

	auto size(size_type index_) {
		return size_[root(index_)];
	}

	auto same(size_type ai, size_type bi) {
		return root(ai) == root(bi);
	}

	auto unite(size_type ai, size_type bi) {
		auto ar = root(ai);
		auto br = root(bi);

		if (ar == br)
			return;

		const auto as = size(ar);
		const auto bs = size(br);

		if (as >= bs)
			std::swap(ar, br);

		par[br] = par[ar];

		if(as == bs)
			size_[ar] = size_[br] = as + bs + 1;

	}

};

int main() {

	ui32 n, m, q;

	std::cin >> n >> m;
	union_find uf(n);
	for (ui32 i{}; i < m; ++i) {
		ui32 s, t;
		std::cin >> s >> t;
		uf.unite(s, t);
	}

	std::cin >> q;
	for (ui32 i{}; i < q; ++i) {
		ui32 s, t; 
		std::cin >> s >> t;
		const auto ans = uf.same(s, t)?"yes":"no";
		std::cout << ans << "\n";
	}
	return 0;
}

C++: #include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=100005;
vector<int> G[MAX];
bool vis[MAX];
int group[MAX];
int n,m,number=0;
void dfs(int u){
	group[u]=number;
	vis[u]=1;
	for(unsigned int i=0;i<G[u].size();i++){
		if(!vis[G[u][i]])dfs(G[u][i]);
	}
}
int main(){
	int q;
	cin>>n>>m;
	for(int i=0;i<m;i++){
		int u,v;
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	for(int i=0;i<n;i++){
			if(!vis[i]){
				dfs(i);
				number++;
			}
		}
	cin>>q;
	for(int i=0;i<q;i++){
		int u,v;
		cin>>u>>v;
		printf("%s\n",((group[u]==group[v])?"yes":"no"));
	}
}