package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
)

func Init() {
}

func Solve(io *FastIO) {
	N := io.NextInt()
	M := io.NextInt()
	Q := io.NextInt()

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

	for i := 0; i < M; i++ {
	  A := io.NextInt()
	  B := io.NextInt()

	  nodes[A].next = append(nodes[A].next, nodes[B])
	  nodes[B].next = append(nodes[B].next, nodes[A])
	}

	seen := make([]bool, N + 1)
	diam := make([]int, N + 1)
	djs := NewDisjointSet(N + 1)
	for i := 1; i <= N; i++ {
	  if seen[i] {
	    continue
	  }
	  cmp := GetComponent(nodes[i])
	  root, _ := FarthestNode(cmp[0], nil)
	  _, dist := FarthestNode(root, nil)
	  for _, u := range cmp {
	    seen[u.id] = true
	  }
	  for j := 1; j < len(cmp); j++ {
	    djs.union(cmp[0].id, cmp[j].id)
	  }
	  part := djs.find(cmp[0].id)
	  diam[part] = dist
	}

	for q := 0; q < Q; q++ {
	  T := io.NextInt()

	  switch T {
	    case 1: {
	      X := io.NextInt()

	      part := djs.find(X)
	      io.Println(diam[part])
	    }
	    case 2: {
	      X := io.NextInt()
	      Y := io.NextInt()

	      partX := djs.find(X)
	      partY := djs.find(Y)
	      if partX != partY {
	       // diamX := diam[partX]
	       // diamY := diam[partY]
	       // longDiam := Max(diamX, diamY)
	       // shortDiam := Min(diamX, diamY)
	       // shortFold := (shortDiam + 1) >> 1
	        dist := CombineDiameters(diam[partX], diam[partY])
	        djs.union(X, Y)
	        part := djs.find(X)
	        diam[part] = dist
	      }
	    }
	  }
	}

// 	fmt.Println(CombineDiameters(0, 0))
// 	fmt.Println(CombineDiameters(0, 1))
// 	fmt.Println(CombineDiameters(0, 2))
// 	fmt.Println(CombineDiameters(1, 1))
// 	fmt.Println(CombineDiameters(1, 2))
// 	fmt.Println(CombineDiameters(2, 2))
}

func CombineDiameters(x, y int) int {
  longDiam := Max(x, y)
  shortDiam := Min(x, y)
  dist := Max(longDiam, 1 + ((longDiam + 1) >> 1) + ((shortDiam + 1) >> 1))
  // fmt.Println(longDiam, shortDiam, "->", dist)
  return dist
  if longDiam == shortDiam {
    return longDiam + 1
  }
  shortFold := (shortDiam + 1) >> 1
  return shortFold + 1 + Max(shortFold + 1, longDiam - shortFold - 1)
}

type Node struct {
  next []*Node
  id int
}

func NewNode(i int) *Node {
  return &Node{
    id: i,
    next: make([]*Node, 0),
  }
}

func FarthestNode(u, p *Node) (*Node, int) {
  far := u
  dist := 0
  for _, v := range u.next {
    if v == p {
      continue
    }
    f, d := FarthestNode(v, u)
    if d >= dist {
      far = f
      dist = d + 1
    }
  }
  return far, dist
}

func componentHelper(u *Node, seen map[*Node]bool) {
  seen[u] = true
  for _, v := range u.next {
    if !seen[v] {
      componentHelper(v, seen)
    }
  }
}

func GetComponent(u *Node) []*Node {
  seen := make(map[*Node]bool)
  componentHelper(u, seen)
  comp := make([]*Node, 0, len(seen))
  for u := range seen {
    comp = append(comp, u)
  }
  return comp
}

type DisjointSet struct {
	parent []int
	rank []int
}

func NewDisjointSet(n int) *DisjointSet {
	dj := DisjointSet{
		parent: make([]int, n),
		rank: make([]int, n),
	}
	for i := 0; i < n; i++ {
		dj.parent[i] = i
	}
	return &dj
}

func (dj *DisjointSet) find(x int) int {
	if dj.parent[x] != x {
		dj.parent[x] = dj.find(dj.parent[x])
	}
	return dj.parent[x]
}

func (dj *DisjointSet) union(x, y int) bool {
	xr := dj.find(x)
	yr := dj.find(y)

	if xr == yr {
		return false
	}

	if dj.rank[xr] < dj.rank[yr] {
		dj.parent[xr] = yr
	} else if dj.rank[xr] > dj.rank[yr] {
		dj.parent[yr] = xr
	} else {
		dj.parent[xr] = yr
		dj.rank[yr]++
	}
	return true
}

func Min(args ...int) int {
	min := args[0]
	for i := 1; i < len(args); i++ {
		if args[i] < min {
			min = args[i]
		}
	}
	return min
}

func Max(args ...int) int {
	max := args[0]
	for i := 1; i < len(args); i++ {
		if args[i] > max {
			max = args[i]
		}
	}
	return max
}

type FastIO struct {
	reader *bufio.Reader
	writer *bufio.Writer
}

func (io *FastIO) NextChar() byte {
	c, _ := io.reader.ReadByte()
	return c
}

func (io *FastIO) NextInt() int {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := 1
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := 0
	for !IsSpaceChar(c) {
		res = (res * 10) + int(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextLong() int64 {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := int64(1)
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := int64(0)
	for !IsSpaceChar(c) {
		res = (res * 10) + int64(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextIntArray(size int) []int {
	return io.NextIntArrayOffset(size, 0)
}

func (io *FastIO) NextIntArrayOffset(size, offset int) []int {
	arr := make([]int, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextInt()
	}
	return arr
}

func (io *FastIO) NextLongArray(size int) []int64 {
	return io.NextLongArrayOffset(size, 0)
}

func (io *FastIO) NextLongArrayOffset(size, offset int) []int64 {
	arr := make([]int64, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextLong()
	}
	return arr
}

func (io *FastIO) NextString() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsSpaceChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) NextLine() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsLineBreakChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) Println(args ...interface{}) {
	io.writer.WriteString(fmt.Sprintln(args...))
}

func (io *FastIO) Printf(format string, args ...interface{}) {
	io.writer.WriteString(fmt.Sprintf(format, args...))
}

func (io *FastIO) FlushOutput() {
	io.writer.Flush()
}

func IsSpaceChar(c byte) bool {
	switch c {
	case 0, '\t', '\n', '\r', ' ':
		return true
	default:
		return false
	}
}

func IsLineBreakChar(c byte) bool {
	switch c {
		case 0, '\n', '\r':
			return true
		default:
			return false
	}
}

func main() {
	io := FastIO{reader: bufio.NewReader(os.Stdin), writer: bufio.NewWriter(os.Stdout)}
	Init()
	Solve(&io)
	io.FlushOutput()
}

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
)

func Init() {
}

func Solve(io *FastIO) {
	N := io.NextInt()
	M := io.NextInt()
	Q := io.NextInt()

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

	for i := 0; i < M; i++ {
	  A := io.NextInt()
	  B := io.NextInt()

	  nodes[A].next = append(nodes[A].next, nodes[B])
	  nodes[B].next = append(nodes[B].next, nodes[A])
	}

	seen := make([]bool, N + 1)
	diam := make([]int, N + 1)
	djs := NewDisjointSet(N + 1)
	for i := 1; i <= N; i++ {
	  if seen[i] {
	    continue
	  }
	  cmp := GetComponent(nodes[i])
	  root, _ := FarthestNode(cmp[0], nil)
	  _, dist := FarthestNode(root, nil)
	  for _, u := range cmp {
	    seen[u.id] = true
	  }
	  for j := 1; j < len(cmp); j++ {
	    djs.union(cmp[0].id, cmp[j].id)
	  }
	  part := djs.find(cmp[0].id)
	  diam[part] = dist
	}

	for q := 0; q < Q; q++ {
	  T := io.NextInt()

	  switch T {
	    case 1: {
	      X := io.NextInt()

	      part := djs.find(X)
	      io.Println(diam[part])
	    }
	    case 2: {
	      X := io.NextInt()
	      Y := io.NextInt()

	      partX := djs.find(X)
	      partY := djs.find(Y)
	      if partX != partY {
	        dist := CombineDiameters(diam[partX], diam[partY])
	        djs.union(X, Y)
	        part := djs.find(X)
	        diam[part] = dist
	      }
	    }
	  }
	}
}

func CombineDiameters(x, y int) int {
  longDiam := Max(x, y)
  shortDiam := Min(x, y)
  return Max(longDiam, 1 + ((longDiam + 1) >> 1) + ((shortDiam + 1) >> 1))
}

type Node struct {
  next []*Node
  id int
}

func NewNode(i int) *Node {
  return &Node{
    id: i,
    next: make([]*Node, 0),
  }
}

func FarthestNode(u, p *Node) (*Node, int) {
  far := u
  dist := 0
  for _, v := range u.next {
    if v == p {
      continue
    }
    f, d := FarthestNode(v, u)
    if d >= dist {
      far = f
      dist = d + 1
    }
  }
  return far, dist
}

func componentHelper(u *Node, seen map[*Node]bool) {
  seen[u] = true
  for _, v := range u.next {
    if !seen[v] {
      componentHelper(v, seen)
    }
  }
}

func GetComponent(u *Node) []*Node {
  seen := make(map[*Node]bool)
  componentHelper(u, seen)
  comp := make([]*Node, 0, len(seen))
  for u := range seen {
    comp = append(comp, u)
  }
  return comp
}

type DisjointSet struct {
	parent []int
	rank []int
}

func NewDisjointSet(n int) *DisjointSet {
	dj := DisjointSet{
		parent: make([]int, n),
		rank: make([]int, n),
	}
	for i := 0; i < n; i++ {
		dj.parent[i] = i
	}
	return &dj
}

func (dj *DisjointSet) find(x int) int {
	if dj.parent[x] != x {
		dj.parent[x] = dj.find(dj.parent[x])
	}
	return dj.parent[x]
}

func (dj *DisjointSet) union(x, y int) bool {
	xr := dj.find(x)
	yr := dj.find(y)

	if xr == yr {
		return false
	}

	if dj.rank[xr] < dj.rank[yr] {
		dj.parent[xr] = yr
	} else if dj.rank[xr] > dj.rank[yr] {
		dj.parent[yr] = xr
	} else {
		dj.parent[xr] = yr
		dj.rank[yr]++
	}
	return true
}

func Min(args ...int) int {
	min := args[0]
	for i := 1; i < len(args); i++ {
		if args[i] < min {
			min = args[i]
		}
	}
	return min
}

func Max(args ...int) int {
	max := args[0]
	for i := 1; i < len(args); i++ {
		if args[i] > max {
			max = args[i]
		}
	}
	return max
}

type FastIO struct {
	reader *bufio.Reader
	writer *bufio.Writer
}

func (io *FastIO) NextChar() byte {
	c, _ := io.reader.ReadByte()
	return c
}

func (io *FastIO) NextInt() int {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := 1
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := 0
	for !IsSpaceChar(c) {
		res = (res * 10) + int(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextLong() int64 {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := int64(1)
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := int64(0)
	for !IsSpaceChar(c) {
		res = (res * 10) + int64(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextIntArray(size int) []int {
	return io.NextIntArrayOffset(size, 0)
}

func (io *FastIO) NextIntArrayOffset(size, offset int) []int {
	arr := make([]int, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextInt()
	}
	return arr
}

func (io *FastIO) NextLongArray(size int) []int64 {
	return io.NextLongArrayOffset(size, 0)
}

func (io *FastIO) NextLongArrayOffset(size, offset int) []int64 {
	arr := make([]int64, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextLong()
	}
	return arr
}

func (io *FastIO) NextString() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsSpaceChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) NextLine() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsLineBreakChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) Println(args ...interface{}) {
	io.writer.WriteString(fmt.Sprintln(args...))
}

func (io *FastIO) Printf(format string, args ...interface{}) {
	io.writer.WriteString(fmt.Sprintf(format, args...))
}

func (io *FastIO) FlushOutput() {
	io.writer.Flush()
}

func IsSpaceChar(c byte) bool {
	switch c {
	case 0, '\t', '\n', '\r', ' ':
		return true
	default:
		return false
	}
}

func IsLineBreakChar(c byte) bool {
	switch c {
		case 0, '\n', '\r':
			return true
		default:
			return false
	}
}

func main() {
	io := FastIO{reader: bufio.NewReader(os.Stdin), writer: bufio.NewWriter(os.Stdout)}
	Init()
	Solve(&io)
	io.FlushOutput()
}

package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime/pprof"
	"strconv"
	"time"
	"unicode/utf8"
	"math/rand"
)

// ******************************** CODE STARTS ********************************

var (
	dsu []int
)

func newDsu(n int) {
	dsu = make([]int, n)
	for i := 0; i < n; i++ {
		dsu[i] = i
	}
}

func getDsu(v int) int {
	if dsu[v] != v {
		dsu[v] = getDsu(dsu[v])
	}
	return dsu[v]
}

func joinDsu(a, b int) {
	a = getDsu(a)
	b = getDsu(b)
	if (rand.Int() & 1) == 1 {
		a, b = b, a
	}
	dsu[a] = b
}

var (
	G [][]int
	was []bool
	L, D, V []int
)

func dfs(v, p, d int) {
	was[v] = true
	V = append(V, v)
	D[v] = d
	for i := 0; i < len(G[v]); i++ {
		if G[v][i] != p {
			dfs(G[v][i], v, d + 1)
		}
	}
}

func solve() {
	n := readInt()
	m := readInt()
	q := readInt()

	G = make([][]int, n)
//	logln(m)
	newDsu(n)
	for i := 0; i < m; i++ {
		a := readInt() - 1
		b := readInt() - 1
		G[a] = append(G[a], b)
		G[b] = append(G[b], a)
		joinDsu(a, b)
	}

	was = make([]bool, n)
	D = make([]int, n)
	L = make([]int, n)

	for v := 0; v < n; v++ {
		if !was[v] {
			V = V[:0]
			dfs(v, -1, 0)
//			logln(D)
			max := v
			for i := 0; i < len(V); i++ {
				if D[max] < D[V[i]] {
					max = V[i]
				}
			}
			V = V[:0]
//			logln(max)
			dfs(max, -1, 0)
//			logln(D)
			max = v
			for i := 0; i < len(V); i++ {
				if D[max] < D[V[i]] {
					max = V[i]
				}
			}
//			logln(max)
			L[getDsu(max)] = D[max]
		}
	}
//	logln("lol")
//	logln(L[getDsu(3)])
//	logln("lol")

	for ; q > 0; q-- {
		t := readInt()
		if t == 1 {
			v := readInt() - 1
//			logln(v)
			printInt(L[getDsu(v)])
			printLine()
		} else {
			a := readInt() - 1
			b := readInt() - 1
//			logln(a)
//			logln(b)
			if getDsu(a) != getDsu(b) {
				lenA := L[getDsu(a)]
				lenB := L[getDsu(b)]
				joinDsu(a, b)
				L[getDsu(a)] = maxInt((lenA + 1) / 2 + (lenB + 1) / 2 + 1, maxInt(lenA,
					lenB))
			}
		}
	}
}

// ********************************* CODE ENDS *********************************

// IO.

var (
	scanner *Scanner
	writer  *bufio.Writer
	logger  *log.Logger
)

func main() {
	dbg := flag.Bool("dbg", false, "Equals true, if run is in debug mode.")
	opt := flag.Bool("opt", false, "Equals true, if run is in optimized mode.")
	flag.Parse()

	var (
		input  *os.File
		output *os.File
	)

	if *opt || *dbg {
		startTime := time.Now()
		defer func() {
			println(fmt.Sprintf("Time: %.5fs", time.Since(startTime).Seconds()))
		}()
		input, _ = os.Open("/home/outside/coding/workspace/go/io/input.txt")
		output, _ = os.Create("/home/outside/coding/workspace/go/io/output.txt")
		logger = log.New(output, "log: ", 0)
		if *dbg {
			cpuprofile, _ := os.Create("/home/outside/coding/workspace/go/io/cpuprofile.txt")
			pprof.StartCPUProfile(cpuprofile)
			defer cpuprofile.Close()
			defer pprof.StopCPUProfile()
		}
	} else {
		input = os.Stdin
		output = os.Stdout
		// input, _ = os.Open("")
		// output, _ = os.Create("")
	}
	defer input.Close()
	defer output.Close()

	scanner = NewScanner(input)
	scanner.Split(bufio.ScanWords)

	writer = bufio.NewWriter(output)
	defer writer.Flush()

	rand.Seed(int64(time.Now().Nanosecond()))
	solve()
}

// Read.

func readString() string {
	scanner.Scan()
	ans := scanner.Text()
	return ans
}

func readLine() string {
	scanner.Split(bufio.ScanLines)
	defer scanner.Split(bufio.ScanWords)
	return readString()
}

func readInt() int {
	ans, _ := strconv.ParseInt(readString(), 10, 0)
	return int(ans)
}

func readInt64() int64 {
	ans, _ := strconv.ParseInt(readString(), 10, 64)
	return ans
}

func readFloat64() float64 {
	ans, _ := strconv.ParseFloat(readString(), 64)
	return ans
}

// Write.

func printString(value string) {
	writer.WriteString(value)
}

func printLine() {
	printString("\n")
}

func printInt(value int) {
	printString(strconv.FormatInt(int64(value), 10))
}

func printInt64(value int64) {
	printString(strconv.FormatInt(value, 10))
}

func printFLoat64(value float64) {
	printString(strconv.FormatFloat(value, 'f', 20, 64))
}

// Log.

func logln(value ...interface{}) {
	writer.Flush()
	logger.Println(value...)
}
func logf(format string, value ...interface{}) {
	writer.Flush()
	logger.Printf(format, value...)
}

// Tuple

type Tuple struct {
	a, b int
}

func (p Tuple) Equals(key Key) bool {
	return p.a == key.(Tuple).a
}

func (p Tuple) Less(key Key) bool {
	return p.a < key.(Tuple).a
}

type TupleSlice []Tuple

func (p TupleSlice) Len() int {
	return len(p)
}

func (p TupleSlice) Less(j, i int) bool {
	return p[j].a < p[i].a
}

func (p TupleSlice) Swap(j, i int) {
	p[j], p[i] = p[i], p[j]
}

// Min, max, abs.

func maxInt(a, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

func minInt(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}

func absInt(a int) int {
	if a > 0 {
		return a
	} else {
		return -a
	}
}

func maxInt64(a, b int64) int64 {
	if a > b {
		return a
	} else {
		return b
	}
}

func minInt64(a, b int64) int64 {
	if a < b {
		return a
	} else {
		return b
	}
}

func absInt64(a int64) int64 {
	if a > 0 {
		return a
	} else {
		return -a
	}
}

func maxFloat64(a, b float64) float64 {
	if a > b {
		return a
	} else {
		return b
	}
}

func minFloat64(a, b float64) float64 {
	if a < b {
		return a
	} else {
		return b
	}
}

func absFloat64(a float64) float64 {
	if a > 0 {
		return a
	} else {
		return -a
	}
}

// Set Key interface implementations.

type Int int

func (p Int) Equals(key Key) bool {
	return int(p) == int(key.(Int))
}

func (p Int) Less(key Key) bool {
	return int(p) < int(key.(Int))
}

// Set.

type Key interface {
	Equals(key Key) bool
	Less(key Key) bool
}

type node struct {
	key   Key
	left  *node
	right *node
}

func newNode(key Key) *node {
	return &node{key, nil, nil}
}

type SplayTree struct {
	root *node
	tmp  *node
	len  int
}

func NewSplayTree() *SplayTree {
	return &SplayTree{nil, newNode(nil), 0}
}

func rotateLeft(x, p *node) {
	p.right = x.left
	x.left = p
}

func rotateRight(x, p *node) {
	p.left = x.right
	x.right = p
}

func (p *SplayTree) splay(x *node, key Key) *node {
	if x == nil {
		return nil
	}

	left := p.tmp
	right := p.tmp

	for {
		if key.Less(x.key) {
			y := x.left
			if y == nil {
				break
			}
			if key.Less(y.key) { // zig-zig
				rotateRight(y, x)
				x = y
				if x.left == nil {
					break
				}
			}
			// link right
			right.left = x
			right = x
			// move left
			x = x.left
		} else if x.key.Less(key) {
			y := x.right
			if y == nil {
				break
			}
			if y.key.Less(key) { // zig-zig
				rotateLeft(y, x)
				x = y
				if x.right == nil {
					break
				}
			}
			// link left
			left.right = x
			left = x
			// move right
			x = x.right
		} else {
			break
		}
	}

	left.right = x.left
	right.left = x.right
	x.left = p.tmp.right
	x.right = p.tmp.left

	return x
}

// left <= key < right
func (p *SplayTree) split(key Key) (left, right *node) {
	p.root = p.splay(p.root, key)
	if p.root.key.Equals(key) || p.root.key.Less(key) {
		right := p.root.right
		p.root.right = nil
		return p.root, right
	} else {
		left := p.root.left
		p.root.left = nil
		return left, p.root
	}
}

// keys from left tree must be less then keys from right tree
func (p *SplayTree) join(left, right *node) *node {
	if left == nil {
		return right
	} else if right == nil {
		return left
	}
	left = p.splay(left, right.key)
	left.right = right
	return left
}

type Set interface {
	Len() int
	Insert(key Key) error
	Find(key Key) bool
	Remove(key Key) error
}

func NewSet() Set {
	return Set(NewSplayTree())
}

func (p *SplayTree) Len() int {
	return p.len
}

func (p *SplayTree) Insert(key Key) error {
	if p.root == nil {
		p.root = newNode(key)
		p.len++
	} else {
		p.root = p.splay(p.root, key)
		if p.root.key.Equals(key) {
			return errors.New("Such key already exists")
		} else {
			left, right := p.split(key)
			p.root = newNode(key)
			p.root.left = left
			p.root.right = right
			p.len++
		}
	}
	return nil
}

func (p *SplayTree) Find(key Key) bool {
	if p.root == nil {
		return false
	}
	p.root = p.splay(p.root, key)
	return p.root.key.Equals(key)
}

func (p *SplayTree) Remove(key Key) error {
	p.root = p.splay(p.root, key)
	if p.root == nil || !p.root.key.Equals(key) {
		return errors.New("Such key doesn't exist")
	}
	p.root = p.join(p.split(key))
	return nil
}

// Copied scan.go
// Scanner provides a convenient interface for reading data such as
// a file of newline-delimited lines of text. Successive calls to
// the Scan method will step through the 'tokens' of a file, skipping
// the bytes between the tokens. The specification of a token is
// defined by a split function of type SplitFunc; the default split
// function breaks the input into lines with line termination stripped. Split
// functions are defined in this package for scanning a file into
// lines, bytes, UTF-8-encoded runes, and space-delimited words. The
// client may instead provide a custom split function.
//
// Scanning stops unrecoverably at EOF, the first I/O error, or a token too
// large to fit in the buffer. When a scan stops, the reader may have
// advanced arbitrarily far past the last token. Programs that need more
// control over error handling or large tokens, or must run sequential scans
// on a reader, should use bufio.Reader instead.
//
type Scanner struct {
	r            io.Reader // The reader provided by the client.
	split        SplitFunc // The function to split the tokens.
	maxTokenSize int       // Maximum size of a token; modified by tests.
	token        []byte    // Last token returned by split.
	buf          []byte    // Buffer used as argument to split.
	start        int       // First non-processed byte in buf.
	end          int       // End of data in buf.
	err          error     // Sticky error.
}

// SplitFunc is the signature of the split function used to tokenize the
// input. The arguments are an initial substring of the remaining unprocessed
// data and a flag, atEOF, that reports whether the Reader has no more data
// to give. The return values are the number of bytes to advance the input
// and the next token to return to the user, plus an error, if any. If the
// data does not yet hold a complete token, for instance if it has no newline
// while scanning lines, SplitFunc can return (0, nil, nil) to signal the
// Scanner to read more data into the slice and try again with a longer slice
// starting at the same point in the input.
//
// If the returned error is non-nil, scanning stops and the error
// is returned to the client.
//
// The function is never called with an empty data slice unless atEOF
// is true. If atEOF is true, however, data may be non-empty and,
// as always, holds unprocessed text.
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

// Errors returned by Scanner.
var (
	ErrTooLong         = errors.New("bufio.Scanner: token too long")
	ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count")
	ErrAdvanceTooFar   = errors.New("bufio.Scanner: SplitFunc returns advance count beyond input")
)

const (
	// Maximum size used to buffer a token. The actual maximum token size
	// may be smaller as the buffer may need to include, for instance, a newline.
	MaxScanTokenSize = 1 << 20
)

// NewScanner returns a new Scanner to read from r.
// The split function defaults to ScanLines.
func NewScanner(r io.Reader) *Scanner {
	return &Scanner{
		r:            r,
		split:        ScanLines,
		maxTokenSize: MaxScanTokenSize,
		buf:          make([]byte, 4096), // Plausible starting size; needn't be large.
	}
}

// Err returns the first non-EOF error that was encountered by the Scanner.
func (s *Scanner) Err() error {
	if s.err == io.EOF {
		return nil
	}
	return s.err
}

// Bytes returns the most recent token generated by a call to Scan.
// The underlying array may point to data that will be overwritten
// by a subsequent call to Scan. It does no allocation.
func (s *Scanner) Bytes() []byte {
	return s.token
}

// Text returns the most recent token generated by a call to Scan
// as a newly allocated string holding its bytes.
func (s *Scanner) Text() string {
	return string(s.token)
}

// Scan advances the Scanner to the next token, which will then be
// available through the Bytes or Text method. It returns false when the
// scan stops, either by reaching the end of the input or an error.
// After Scan returns false, the Err method will return any error that
// occurred during scanning, except that if it was io.EOF, Err
// will return nil.
func (s *Scanner) Scan() bool {
	// Loop until we have a token.
	for {
		// See if we can get a token with what we already have.
		if s.end > s.start {
			advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
			if err != nil {
				s.setErr(err)
				return false
			}
			if !s.advance(advance) {
				return false
			}
			s.token = token
			if token != nil {
				return true
			}
		}
		// We cannot generate a token with what we are holding.
		// If we've already hit EOF or an I/O error, we are done.
		if s.err != nil {
			// Shut it down.
			s.start = 0
			s.end = 0
			return false
		}
		// Must read more data.
		// First, shift data to beginning of buffer if there's lots of empty space
		// or space is neded.
		if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
			copy(s.buf, s.buf[s.start:s.end])
			s.end -= s.start
			s.start = 0
		}
		// Is the buffer full? If so, resize.
		if s.end == len(s.buf) {
			if len(s.buf) >= s.maxTokenSize {
				s.setErr(ErrTooLong)
				return false
			}
			newSize := len(s.buf) * 2
			if newSize > s.maxTokenSize {
				newSize = s.maxTokenSize
			}
			newBuf := make([]byte, newSize)
			copy(newBuf, s.buf[s.start:s.end])
			s.buf = newBuf
			s.end -= s.start
			s.start = 0
			continue
		}
		// Finally we can read some input. Make sure we don't get stuck with
		// a misbehaving Reader. Officially we don't need to do this, but let's
		// be extra careful: Scanner is for safe, simple jobs.
		for loop := 0; ; {
			n, err := s.r.Read(s.buf[s.end:len(s.buf)])
			s.end += n
			if err != nil {
				s.setErr(err)
				break
			}
			if n > 0 {
				break
			}
			loop++
			if loop > 100 {
				s.setErr(io.ErrNoProgress)
				break
			}
		}
	}
}

// advance consumes n bytes of the buffer. It reports whether the advance was legal.
func (s *Scanner) advance(n int) bool {
	if n < 0 {
		s.setErr(ErrNegativeAdvance)
		return false
	}
	if n > s.end-s.start {
		s.setErr(ErrAdvanceTooFar)
		return false
	}
	s.start += n
	return true
}

// setErr records the first error encountered.
func (s *Scanner) setErr(err error) {
	if s.err == nil || s.err == io.EOF {
		s.err = err
	}
}

// Split sets the split function for the Scanner. If called, it must be
// called before Scan. The default split function is ScanLines.
func (s *Scanner) Split(split SplitFunc) {
	s.split = split
}

// Split functions

// ScanBytes is a split function for a Scanner that returns each byte as a token.
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	return 1, data[0:1], nil
}

var errorRune = []byte(string(utf8.RuneError))

// ScanRunes is a split function for a Scanner that returns each
// UTF-8-encoded rune as a token. The sequence of runes returned is
// equivalent to that from a range loop over the input as a string, which
// means that erroneous UTF-8 encodings translate to U+FFFD = "\xef\xbf\xbd".
// Because of the Scan interface, this makes it impossible for the client to
// distinguish correctly encoded replacement runes from encoding errors.
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}

	// Fast path 1: ASCII.
	if data[0] < utf8.RuneSelf {
		return 1, data[0:1], nil
	}

	// Fast path 2: Correct UTF-8 decode without error.
	_, width := utf8.DecodeRune(data)
	if width > 1 {
		// It's a valid encoding. Width cannot be one for a correctly encoded
		// non-ASCII rune.
		return width, data[0:width], nil
	}

	// We know it's an error: we have width==1 and implicitly r==utf8.RuneError.
	// Is the error because there wasn't a full rune to be decoded?
	// FullRune distinguishes correctly between erroneous and incomplete encodings.
	if !atEOF && !utf8.FullRune(data) {
		// Incomplete; get more bytes.
		return 0, nil, nil
	}

	// We have a real UTF-8 encoding error. Return a properly encoded error rune
	// but advance only one byte. This matches the behavior of a range loop over
	// an incorrectly encoded string.
	return 1, errorRune, nil
}

// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
	if len(data) > 0 && data[len(data)-1] == '\r' {
		return data[0 : len(data)-1]
	}
	return data
}

// ScanLines is a split function for a Scanner that returns each line of
// text, stripped of any trailing end-of-line marker. The returned line may
// be empty. The end-of-line marker is one optional carriage return followed
// by one mandatory newline. In regular expression notation, it is `\r?\n`.
// The last non-empty line of input will be returned even if it has no
// newline.
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\n'); i >= 0 {
		// We have a full newline-terminated line.
		return i + 1, dropCR(data[0:i]), nil
	}
	// If we're at EOF, we have a final, non-terminated line. Return it.
	if atEOF {
		return len(data), dropCR(data), nil
	}
	// Request more data.
	return 0, nil, nil
}

// isSpace reports whether the character is a Unicode white space character.
// We avoid dependency on the unicode package, but check validity of the implementation
// in the tests.
func isSpace(r rune) bool {
	if r <= '\u00FF' {
		// Obvious ASCII ones: \t through \r plus space. Plus two Latin-1 oddballs.
		switch r {
		case ' ', '\t', '\n', '\v', '\f', '\r':
			return true
		case '\u0085', '\u00A0':
			return true
		}
		return false
	}
	// High-valued ones.
	if '\u2000' <= r && r <= '\u200a' {
		return true
	}
	switch r {
	case '\u1680', '\u180e', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
		return true
	}
	return false
}

// ScanWords is a split function for a Scanner that returns each
// space-separated word of text, with surrounding spaces deleted. It will
// never return an empty string. The definition of space is set by
// unicode.IsSpace.
func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
	// Skip leading spaces.
	start := 0
	for width := 0; start < len(data); start += width {
		var r rune
		r, width = utf8.DecodeRune(data[start:])
		if !isSpace(r) {
			break
		}
	}
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	// Scan until space, marking end of word.
	for width, i := 0, start; i < len(data); i += width {
		var r rune
		r, width = utf8.DecodeRune(data[i:])
		if isSpace(r) {
			return i + width, data[start:i], nil
		}
	}
	// If we're at EOF, we have a final, non-empty, non-terminated word. Return it.
	if atEOF && len(data) > start {
		return len(data), data[start:], nil
	}
	// Request more data.
	return 0, nil, nil
}

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func CF455C(_r io.Reader, _w io.Writer) {
	out := bufio.NewWriter(_w)
	defer out.Flush()
	buf := make([]byte, 4096)
	_i := len(buf)
	rc := func() byte {
		if _i == len(buf) {
			_r.Read(buf)
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		for ; '0' > b; b = rc() {
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		return
	}

	var u, core, maxD int
	n, m, q := r(), r(), r()
	g := make([][]int, n)
	for i := 0; i < m; i++ {
		v, w := r()-1, r()-1
		g[v] = append(g[v], w)
		g[w] = append(g[w], v)
	}

	size := make([]int, n)
	fa := make([]int, n)
	var find func(int) int
	find = func(x int) int {
		if fa[x] != x {
			fa[x] = find(fa[x])
		}
		return fa[x]
	}
	merge := func(from, to int) {
		from, to = find(from), find(to)
		if from == to {
			return
		}
		sf, st := size[from], size[to]
		s1, s2 := (sf+1)/2, (st+1)/2
		if s1 > s2 {
			s1, s2 = s2, s1
		}
		if s1+1 >= s2 {
			size[to] = s1 + s2 + 1
		} else if sf > st {
			size[to] = sf
		} else {
			size[to] = st
		}
		fa[from] = to
	}

	vis := make([]bool, n)
	var f func(v, p, d int)
	f = func(v, p, d int) {
		vis[v] = true
		fa[v] = core
		if d > maxD {
			maxD = d
			u = v
		}
		for _, w := range g[v] {
			if w != p {
				f(w, v, d+1)
			}
		}
	}
	for i, b := range vis {
		if !b {
			core = i
			maxD = -1
			f(i, -1, 0)
			maxD = -1
			f(u, -1, 0)
			size[i] = maxD
		}
	}

	for ; q > 0; q-- {
		if r() == 1 {
			Fprintln(out, size[find(r()-1)])
		} else {
			merge(r()-1, r()-1)
		}
	}
}

func main() { CF455C(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func CF455C(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var n, m, q, v, w, u, core, maxD, op int
	Fscan(in, &n, &m, &q)
	g := make([][]int, n)
	for i := 0; i < m; i++ {
		Fscan(in, &v, &w)
		v--
		w--
		g[v] = append(g[v], w)
		g[w] = append(g[w], v)
	}

	size := make([]int, n)
	fa := make([]int, n)
	var find func(int) int
	find = func(x int) int {
		if fa[x] != x {
			fa[x] = find(fa[x])
		}
		return fa[x]
	}
	merge := func(from, to int) {
		from, to = find(from), find(to)
		if from == to {
			return
		}
		sf, st := size[from], size[to]
		s1, s2 := (sf+1)/2, (st+1)/2
		if s1 > s2 {
			s1, s2 = s2, s1
		}
		if s1+1 >= s2 {
			size[to] = s1 + s2 + 1
		} else if sf > st {
			size[to] = sf
		} else {
			size[to] = st
		}
		fa[from] = to
	}

	vis := make([]bool, n)
	var f func(v, p, d int)
	f = func(v, p, d int) {
		vis[v] = true
		fa[v] = core
		if d > maxD {
			maxD = d
			u = v
		}
		for _, w := range g[v] {
			if w != p {
				f(w, v, d+1)
			}
		}
	}
	for i, b := range vis {
		if !b {
			core = i
			maxD = -1
			f(i, -1, 0)
			maxD = -1
			f(u, -1, 0)
			size[i] = maxD
		}
	}

	for ; q > 0; q-- {
		Fscan(in, &op, &v)
		if op == 1 {
			Fprintln(out, size[find(v-1)])
		} else {
			Fscan(in, &w)
			merge(v-1, w-1)
		}
	}
}

func main() { CF455C(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime/pprof"
	"strconv"
	"time"
	"unicode/utf8"
	"math/rand"
)

// ******************************** CODE STARTS ********************************

var (
	dsu []int
)

func newDsu(n int) {
	dsu = make([]int, n)
	for i := 0; i < n; i++ {
		dsu[i] = i
	}
}

func getDsu(v int) int {
	if dsu[v] != v {
		dsu[v] = getDsu(dsu[v])
	}
	return dsu[v]
}

func joinDsu(a, b int) {
	a = getDsu(a)
	b = getDsu(b)
	if (rand.Int() & 1) == 1 {
		a, b = b, a
	}
	dsu[a] = b
}

var (
	G [][]int
	was []bool
	L, D, V []int
)

func dfs(v, p, d int) {
	was[v] = true
	V = append(V, v)
	D[v] = d
	for i := 0; i < len(G[v]); i++ {
		if G[v][i] != p {
			dfs(G[v][i], v, d + 1)
		}
	}
}

func solve() {
	n := readInt()
	m := readInt()
	q := readInt()

	G = make([][]int, n)
//	logln(m)
	newDsu(n)
	for i := 0; i < m; i++ {
		a := readInt() - 1
		b := readInt() - 1
		G[a] = append(G[a], b)
		G[b] = append(G[b], a)
		joinDsu(a, b)
	}

	was = make([]bool, n)
	D = make([]int, n)
	L = make([]int, n)

	for v := 0; v < n; v++ {
		if !was[v] {
			V = V[:0]
			dfs(v, -1, 0)
			max := v
			for i := 0; i < len(V); i++ {
				if D[max] < D[V[i]] {
					max = V[i]
				}
			}
			V = V[:0]
			dfs(max, -1, 0)
			max = v
			for i := 0; i < len(V); i++ {
				if D[max] < D[V[i]] {
					max = V[i]
				}
			}
			L[getDsu(max)] = D[max]
		}
	}
//	logln("lol")

	for ; q > 0; q-- {
		t := readInt()
		if t == 1 {
			v := readInt() - 1
//			logln(v)
			printInt(L[getDsu(v)])
			printLine()
		} else {
			a := readInt() - 1
			b := readInt() - 1
//			logln(a)
//			logln(b)
			lenA := L[getDsu(a)]
			lenB := L[getDsu(b)]
			joinDsu(a, b)
			L[getDsu(a)] = (lenA + 1) / 2 + (lenB + 1) / 2 + 1
		}
	}
}

// ********************************* CODE ENDS *********************************

// IO.

var (
	scanner *Scanner
	writer  *bufio.Writer
	logger  *log.Logger
)

func main() {
	dbg := flag.Bool("dbg", false, "Equals true, if run is in debug mode.")
	opt := flag.Bool("opt", false, "Equals true, if run is in optimized mode.")
	flag.Parse()

	var (
		input  *os.File
		output *os.File
	)

	if *opt || *dbg {
		startTime := time.Now()
		defer func() {
			println(fmt.Sprintf("Time: %.5fs", time.Since(startTime).Seconds()))
		}()
		input, _ = os.Open("/home/outside/coding/workspace/go/io/input.txt")
		output, _ = os.Create("/home/outside/coding/workspace/go/io/output.txt")
		logger = log.New(output, "log: ", 0)
		if *dbg {
			cpuprofile, _ := os.Create("/home/outside/coding/workspace/go/io/cpuprofile.txt")
			pprof.StartCPUProfile(cpuprofile)
			defer cpuprofile.Close()
			defer pprof.StopCPUProfile()
		}
	} else {
		input = os.Stdin
		output = os.Stdout
		// input, _ = os.Open("")
		// output, _ = os.Create("")
	}
	defer input.Close()
	defer output.Close()

	scanner = NewScanner(input)
	scanner.Split(bufio.ScanWords)

	writer = bufio.NewWriter(output)
	defer writer.Flush()

	rand.Seed(int64(time.Now().Nanosecond()))
	solve()
}

// Read.

func readString() string {
	scanner.Scan()
	ans := scanner.Text()
	return ans
}

func readLine() string {
	scanner.Split(bufio.ScanLines)
	defer scanner.Split(bufio.ScanWords)
	return readString()
}

func readInt() int {
	ans, _ := strconv.ParseInt(readString(), 10, 0)
	return int(ans)
}

func readInt64() int64 {
	ans, _ := strconv.ParseInt(readString(), 10, 64)
	return ans
}

func readFloat64() float64 {
	ans, _ := strconv.ParseFloat(readString(), 64)
	return ans
}

// Write.

func printString(value string) {
	writer.WriteString(value)
}

func printLine() {
	printString("\n")
}

func printInt(value int) {
	printString(strconv.FormatInt(int64(value), 10))
}

func printInt64(value int64) {
	printString(strconv.FormatInt(value, 10))
}

func printFLoat64(value float64) {
	printString(strconv.FormatFloat(value, 'f', 20, 64))
}

// Log.

func logln(value ...interface{}) {
	writer.Flush()
	logger.Println(value...)
}
func logf(format string, value ...interface{}) {
	writer.Flush()
	logger.Printf(format, value...)
}

// Tuple

type Tuple struct {
	a, b int
}

func (p Tuple) Equals(key Key) bool {
	return p.a == key.(Tuple).a
}

func (p Tuple) Less(key Key) bool {
	return p.a < key.(Tuple).a
}

type TupleSlice []Tuple

func (p TupleSlice) Len() int {
	return len(p)
}

func (p TupleSlice) Less(j, i int) bool {
	return p[j].a < p[i].a
}

func (p TupleSlice) Swap(j, i int) {
	p[j], p[i] = p[i], p[j]
}

// Min, max, abs.

func maxInt(a, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

func minInt(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}

func absInt(a int) int {
	if a > 0 {
		return a
	} else {
		return -a
	}
}

func maxInt64(a, b int64) int64 {
	if a > b {
		return a
	} else {
		return b
	}
}

func minInt64(a, b int64) int64 {
	if a < b {
		return a
	} else {
		return b
	}
}

func absInt64(a int64) int64 {
	if a > 0 {
		return a
	} else {
		return -a
	}
}

func maxFloat64(a, b float64) float64 {
	if a > b {
		return a
	} else {
		return b
	}
}

func minFloat64(a, b float64) float64 {
	if a < b {
		return a
	} else {
		return b
	}
}

func absFloat64(a float64) float64 {
	if a > 0 {
		return a
	} else {
		return -a
	}
}

// Set Key interface implementations.

type Int int

func (p Int) Equals(key Key) bool {
	return int(p) == int(key.(Int))
}

func (p Int) Less(key Key) bool {
	return int(p) < int(key.(Int))
}

// Set.

type Key interface {
	Equals(key Key) bool
	Less(key Key) bool
}

type node struct {
	key   Key
	left  *node
	right *node
}

func newNode(key Key) *node {
	return &node{key, nil, nil}
}

type SplayTree struct {
	root *node
	tmp  *node
	len  int
}

func NewSplayTree() *SplayTree {
	return &SplayTree{nil, newNode(nil), 0}
}

func rotateLeft(x, p *node) {
	p.right = x.left
	x.left = p
}

func rotateRight(x, p *node) {
	p.left = x.right
	x.right = p
}

func (p *SplayTree) splay(x *node, key Key) *node {
	if x == nil {
		return nil
	}

	left := p.tmp
	right := p.tmp

	for {
		if key.Less(x.key) {
			y := x.left
			if y == nil {
				break
			}
			if key.Less(y.key) { // zig-zig
				rotateRight(y, x)
				x = y
				if x.left == nil {
					break
				}
			}
			// link right
			right.left = x
			right = x
			// move left
			x = x.left
		} else if x.key.Less(key) {
			y := x.right
			if y == nil {
				break
			}
			if y.key.Less(key) { // zig-zig
				rotateLeft(y, x)
				x = y
				if x.right == nil {
					break
				}
			}
			// link left
			left.right = x
			left = x
			// move right
			x = x.right
		} else {
			break
		}
	}

	left.right = x.left
	right.left = x.right
	x.left = p.tmp.right
	x.right = p.tmp.left

	return x
}

// left <= key < right
func (p *SplayTree) split(key Key) (left, right *node) {
	p.root = p.splay(p.root, key)
	if p.root.key.Equals(key) || p.root.key.Less(key) {
		right := p.root.right
		p.root.right = nil
		return p.root, right
	} else {
		left := p.root.left
		p.root.left = nil
		return left, p.root
	}
}

// keys from left tree must be less then keys from right tree
func (p *SplayTree) join(left, right *node) *node {
	if left == nil {
		return right
	} else if right == nil {
		return left
	}
	left = p.splay(left, right.key)
	left.right = right
	return left
}

type Set interface {
	Len() int
	Insert(key Key) error
	Find(key Key) bool
	Remove(key Key) error
}

func NewSet() Set {
	return Set(NewSplayTree())
}

func (p *SplayTree) Len() int {
	return p.len
}

func (p *SplayTree) Insert(key Key) error {
	if p.root == nil {
		p.root = newNode(key)
		p.len++
	} else {
		p.root = p.splay(p.root, key)
		if p.root.key.Equals(key) {
			return errors.New("Such key already exists")
		} else {
			left, right := p.split(key)
			p.root = newNode(key)
			p.root.left = left
			p.root.right = right
			p.len++
		}
	}
	return nil
}

func (p *SplayTree) Find(key Key) bool {
	if p.root == nil {
		return false
	}
	p.root = p.splay(p.root, key)
	return p.root.key.Equals(key)
}

func (p *SplayTree) Remove(key Key) error {
	p.root = p.splay(p.root, key)
	if p.root == nil || !p.root.key.Equals(key) {
		return errors.New("Such key doesn't exist")
	}
	p.root = p.join(p.split(key))
	return nil
}

// Copied scan.go
// Scanner provides a convenient interface for reading data such as
// a file of newline-delimited lines of text. Successive calls to
// the Scan method will step through the 'tokens' of a file, skipping
// the bytes between the tokens. The specification of a token is
// defined by a split function of type SplitFunc; the default split
// function breaks the input into lines with line termination stripped. Split
// functions are defined in this package for scanning a file into
// lines, bytes, UTF-8-encoded runes, and space-delimited words. The
// client may instead provide a custom split function.
//
// Scanning stops unrecoverably at EOF, the first I/O error, or a token too
// large to fit in the buffer. When a scan stops, the reader may have
// advanced arbitrarily far past the last token. Programs that need more
// control over error handling or large tokens, or must run sequential scans
// on a reader, should use bufio.Reader instead.
//
type Scanner struct {
	r            io.Reader // The reader provided by the client.
	split        SplitFunc // The function to split the tokens.
	maxTokenSize int       // Maximum size of a token; modified by tests.
	token        []byte    // Last token returned by split.
	buf          []byte    // Buffer used as argument to split.
	start        int       // First non-processed byte in buf.
	end          int       // End of data in buf.
	err          error     // Sticky error.
}

// SplitFunc is the signature of the split function used to tokenize the
// input. The arguments are an initial substring of the remaining unprocessed
// data and a flag, atEOF, that reports whether the Reader has no more data
// to give. The return values are the number of bytes to advance the input
// and the next token to return to the user, plus an error, if any. If the
// data does not yet hold a complete token, for instance if it has no newline
// while scanning lines, SplitFunc can return (0, nil, nil) to signal the
// Scanner to read more data into the slice and try again with a longer slice
// starting at the same point in the input.
//
// If the returned error is non-nil, scanning stops and the error
// is returned to the client.
//
// The function is never called with an empty data slice unless atEOF
// is true. If atEOF is true, however, data may be non-empty and,
// as always, holds unprocessed text.
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

// Errors returned by Scanner.
var (
	ErrTooLong         = errors.New("bufio.Scanner: token too long")
	ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count")
	ErrAdvanceTooFar   = errors.New("bufio.Scanner: SplitFunc returns advance count beyond input")
)

const (
	// Maximum size used to buffer a token. The actual maximum token size
	// may be smaller as the buffer may need to include, for instance, a newline.
	MaxScanTokenSize = 1 << 20
)

// NewScanner returns a new Scanner to read from r.
// The split function defaults to ScanLines.
func NewScanner(r io.Reader) *Scanner {
	return &Scanner{
		r:            r,
		split:        ScanLines,
		maxTokenSize: MaxScanTokenSize,
		buf:          make([]byte, 4096), // Plausible starting size; needn't be large.
	}
}

// Err returns the first non-EOF error that was encountered by the Scanner.
func (s *Scanner) Err() error {
	if s.err == io.EOF {
		return nil
	}
	return s.err
}

// Bytes returns the most recent token generated by a call to Scan.
// The underlying array may point to data that will be overwritten
// by a subsequent call to Scan. It does no allocation.
func (s *Scanner) Bytes() []byte {
	return s.token
}

// Text returns the most recent token generated by a call to Scan
// as a newly allocated string holding its bytes.
func (s *Scanner) Text() string {
	return string(s.token)
}

// Scan advances the Scanner to the next token, which will then be
// available through the Bytes or Text method. It returns false when the
// scan stops, either by reaching the end of the input or an error.
// After Scan returns false, the Err method will return any error that
// occurred during scanning, except that if it was io.EOF, Err
// will return nil.
func (s *Scanner) Scan() bool {
	// Loop until we have a token.
	for {
		// See if we can get a token with what we already have.
		if s.end > s.start {
			advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
			if err != nil {
				s.setErr(err)
				return false
			}
			if !s.advance(advance) {
				return false
			}
			s.token = token
			if token != nil {
				return true
			}
		}
		// We cannot generate a token with what we are holding.
		// If we've already hit EOF or an I/O error, we are done.
		if s.err != nil {
			// Shut it down.
			s.start = 0
			s.end = 0
			return false
		}
		// Must read more data.
		// First, shift data to beginning of buffer if there's lots of empty space
		// or space is neded.
		if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
			copy(s.buf, s.buf[s.start:s.end])
			s.end -= s.start
			s.start = 0
		}
		// Is the buffer full? If so, resize.
		if s.end == len(s.buf) {
			if len(s.buf) >= s.maxTokenSize {
				s.setErr(ErrTooLong)
				return false
			}
			newSize := len(s.buf) * 2
			if newSize > s.maxTokenSize {
				newSize = s.maxTokenSize
			}
			newBuf := make([]byte, newSize)
			copy(newBuf, s.buf[s.start:s.end])
			s.buf = newBuf
			s.end -= s.start
			s.start = 0
			continue
		}
		// Finally we can read some input. Make sure we don't get stuck with
		// a misbehaving Reader. Officially we don't need to do this, but let's
		// be extra careful: Scanner is for safe, simple jobs.
		for loop := 0; ; {
			n, err := s.r.Read(s.buf[s.end:len(s.buf)])
			s.end += n
			if err != nil {
				s.setErr(err)
				break
			}
			if n > 0 {
				break
			}
			loop++
			if loop > 100 {
				s.setErr(io.ErrNoProgress)
				break
			}
		}
	}
}

// advance consumes n bytes of the buffer. It reports whether the advance was legal.
func (s *Scanner) advance(n int) bool {
	if n < 0 {
		s.setErr(ErrNegativeAdvance)
		return false
	}
	if n > s.end-s.start {
		s.setErr(ErrAdvanceTooFar)
		return false
	}
	s.start += n
	return true
}

// setErr records the first error encountered.
func (s *Scanner) setErr(err error) {
	if s.err == nil || s.err == io.EOF {
		s.err = err
	}
}

// Split sets the split function for the Scanner. If called, it must be
// called before Scan. The default split function is ScanLines.
func (s *Scanner) Split(split SplitFunc) {
	s.split = split
}

// Split functions

// ScanBytes is a split function for a Scanner that returns each byte as a token.
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	return 1, data[0:1], nil
}

var errorRune = []byte(string(utf8.RuneError))

// ScanRunes is a split function for a Scanner that returns each
// UTF-8-encoded rune as a token. The sequence of runes returned is
// equivalent to that from a range loop over the input as a string, which
// means that erroneous UTF-8 encodings translate to U+FFFD = "\xef\xbf\xbd".
// Because of the Scan interface, this makes it impossible for the client to
// distinguish correctly encoded replacement runes from encoding errors.
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}

	// Fast path 1: ASCII.
	if data[0] < utf8.RuneSelf {
		return 1, data[0:1], nil
	}

	// Fast path 2: Correct UTF-8 decode without error.
	_, width := utf8.DecodeRune(data)
	if width > 1 {
		// It's a valid encoding. Width cannot be one for a correctly encoded
		// non-ASCII rune.
		return width, data[0:width], nil
	}

	// We know it's an error: we have width==1 and implicitly r==utf8.RuneError.
	// Is the error because there wasn't a full rune to be decoded?
	// FullRune distinguishes correctly between erroneous and incomplete encodings.
	if !atEOF && !utf8.FullRune(data) {
		// Incomplete; get more bytes.
		return 0, nil, nil
	}

	// We have a real UTF-8 encoding error. Return a properly encoded error rune
	// but advance only one byte. This matches the behavior of a range loop over
	// an incorrectly encoded string.
	return 1, errorRune, nil
}

// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
	if len(data) > 0 && data[len(data)-1] == '\r' {
		return data[0 : len(data)-1]
	}
	return data
}

// ScanLines is a split function for a Scanner that returns each line of
// text, stripped of any trailing end-of-line marker. The returned line may
// be empty. The end-of-line marker is one optional carriage return followed
// by one mandatory newline. In regular expression notation, it is `\r?\n`.
// The last non-empty line of input will be returned even if it has no
// newline.
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\n'); i >= 0 {
		// We have a full newline-terminated line.
		return i + 1, dropCR(data[0:i]), nil
	}
	// If we're at EOF, we have a final, non-terminated line. Return it.
	if atEOF {
		return len(data), dropCR(data), nil
	}
	// Request more data.
	return 0, nil, nil
}

// isSpace reports whether the character is a Unicode white space character.
// We avoid dependency on the unicode package, but check validity of the implementation
// in the tests.
func isSpace(r rune) bool {
	if r <= '\u00FF' {
		// Obvious ASCII ones: \t through \r plus space. Plus two Latin-1 oddballs.
		switch r {
		case ' ', '\t', '\n', '\v', '\f', '\r':
			return true
		case '\u0085', '\u00A0':
			return true
		}
		return false
	}
	// High-valued ones.
	if '\u2000' <= r && r <= '\u200a' {
		return true
	}
	switch r {
	case '\u1680', '\u180e', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
		return true
	}
	return false
}

// ScanWords is a split function for a Scanner that returns each
// space-separated word of text, with surrounding spaces deleted. It will
// never return an empty string. The definition of space is set by
// unicode.IsSpace.
func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
	// Skip leading spaces.
	start := 0
	for width := 0; start < len(data); start += width {
		var r rune
		r, width = utf8.DecodeRune(data[start:])
		if !isSpace(r) {
			break
		}
	}
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	// Scan until space, marking end of word.
	for width, i := 0, start; i < len(data); i += width {
		var r rune
		r, width = utf8.DecodeRune(data[i:])
		if isSpace(r) {
			return i + width, data[start:i], nil
		}
	}
	// If we're at EOF, we have a final, non-empty, non-terminated word. Return it.
	if atEOF && len(data) > start {
		return len(data), data[start:], nil
	}
	// Request more data.
	return 0, nil, nil
}

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func CF455C(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var n, m, q, v, w, u, core, maxD, op int
	Fscan(in, &n, &m, &q)
	g := make([][]int, n)
	for i := 0; i < m; i++ {
		Fscan(in, &v, &w)
		v--
		w--
		g[v] = append(g[v], w)
		g[w] = append(g[w], v)
	}

	size := make([]int, n)
	fa := make([]int, n)
	var find func(int) int
	find = func(x int) int {
		if fa[x] != x {
			fa[x] = find(fa[x])
		}
		return fa[x]
	}
	merge := func(from, to int) {
		from, to = find(from), find(to)
		if from == to {
			return
		}
		s1, s2 := size[from], size[to]
		if s1 > s2 {
			s1, s2 = s2, s1
		}
		sf, st := size[from], size[to]
		s1, s2 = (sf+1)/2, (st+1)/2
		if s1 > s2 {
			s1, s2 = s2, s1
		}
		if s2+1 >= s1 {
			size[to] = s1 + s2 + 1
		} else if sf > st {
			size[to] = sf
		} else {
			size[to] = st
		}
		fa[from] = to
	}

	vis := make([]bool, n)
	var f func(v, p, d int)
	f = func(v, p, d int) {
		vis[v] = true
		fa[v] = core
		if d > maxD {
			maxD = d
			u = v
		}
		for _, w := range g[v] {
			if w != p {
				f(w, v, d+1)
			}
		}
	}
	for i, b := range vis {
		if !b {
			core = i
			maxD = -1
			f(i, -1, 0)
			maxD = -1
			f(u, -1, 0)
			size[i] = maxD
		}
	}

	for ; q > 0; q-- {
		Fscan(in, &op, &v)
		if op == 1 {
			Fprintln(out, size[find(v-1)])
		} else {
			Fscan(in, &w)
			merge(v-1, w-1)
		}
	}
}

func main() { CF455C(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
)

func Init() {
}

func Solve(io *FastIO) {
	N := io.NextInt()
	M := io.NextInt()
	Q := io.NextInt()

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

	for i := 0; i < M; i++ {
	  A := io.NextInt()
	  B := io.NextInt()

	  nodes[A].next = append(nodes[A].next, nodes[B])
	  nodes[B].next = append(nodes[B].next, nodes[A])
	}

	seen := make([]bool, N + 1)
	diam := make([]int, N + 1)
	djs := NewDisjointSet(N + 1)
	for i := 1; i <= N; i++ {
	  if seen[i] {
	    continue
	  }
	  cmp := GetComponent(nodes[i])
	  root, _ := FarthestNode(cmp[0], nil)
	  _, dist := FarthestNode(root, nil)
	  for _, u := range cmp {
	    seen[u.id] = true
	  }
	  for j := 1; j < len(cmp); j++ {
	    djs.union(cmp[0].id, cmp[j].id)
	  }
	  part := djs.find(cmp[0].id)
	  diam[part] = dist
	}

	for q := 0; q < Q; q++ {
	  T := io.NextInt()

	  switch T {
	    case 1: {
	      X := io.NextInt()

	      part := djs.find(X)
	      io.Println(diam[part])
	    }
	    case 2: {
	      X := io.NextInt()
	      Y := io.NextInt()

	      partX := djs.find(X)
	      partY := djs.find(Y)
	      if partX != partY {
	        diamX := diam[partX]
	        diamY := diam[partY]
	        longDiam := Max(diamX, diamY)
	        shortDiam := Min(diamX, diamY)
	        dist := ((longDiam + 1) >> 1) + Max(longDiam >> 1, 1 + (shortDiam >> 1))
	        djs.union(X, Y)
	        part := djs.find(X)
	        diam[part] = dist
	      }
	    }
	  }
	}
}

type Node struct {
  next []*Node
  id int
}

func NewNode(i int) *Node {
  return &Node{
    id: i,
    next: make([]*Node, 0),
  }
}

func FarthestNode(u, p *Node) (*Node, int) {
  far := u
  dist := 0
  for _, v := range u.next {
    if v == p {
      continue
    }
    f, d := FarthestNode(v, u)
    if d >= dist {
      far = f
      dist = d + 1
    }
  }
  return far, dist
}

func componentHelper(u *Node, seen map[*Node]bool) {
  seen[u] = true
  for _, v := range u.next {
    if !seen[v] {
      componentHelper(v, seen)
    }
  }
}

func GetComponent(u *Node) []*Node {
  seen := make(map[*Node]bool)
  componentHelper(u, seen)
  comp := make([]*Node, 0, len(seen))
  for u := range seen {
    comp = append(comp, u)
  }
  return comp
}

type DisjointSet struct {
	parent []int
	rank []int
}

func NewDisjointSet(n int) *DisjointSet {
	dj := DisjointSet{
		parent: make([]int, n),
		rank: make([]int, n),
	}
	for i := 0; i < n; i++ {
		dj.parent[i] = i
	}
	return &dj
}

func (dj *DisjointSet) find(x int) int {
	if dj.parent[x] != x {
		dj.parent[x] = dj.find(dj.parent[x])
	}
	return dj.parent[x]
}

func (dj *DisjointSet) union(x, y int) bool {
	xr := dj.find(x)
	yr := dj.find(y)

	if xr == yr {
		return false
	}

	if dj.rank[xr] < dj.rank[yr] {
		dj.parent[xr] = yr
	} else if dj.rank[xr] > dj.rank[yr] {
		dj.parent[yr] = xr
	} else {
		dj.parent[xr] = yr
		dj.rank[yr]++
	}
	return true
}

func Min(args ...int) int {
	min := args[0]
	for i := 1; i < len(args); i++ {
		if args[i] < min {
			min = args[i]
		}
	}
	return min
}

func Max(args ...int) int {
	max := args[0]
	for i := 1; i < len(args); i++ {
		if args[i] > max {
			max = args[i]
		}
	}
	return max
}

type FastIO struct {
	reader *bufio.Reader
	writer *bufio.Writer
}

func (io *FastIO) NextChar() byte {
	c, _ := io.reader.ReadByte()
	return c
}

func (io *FastIO) NextInt() int {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := 1
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := 0
	for !IsSpaceChar(c) {
		res = (res * 10) + int(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextLong() int64 {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := int64(1)
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := int64(0)
	for !IsSpaceChar(c) {
		res = (res * 10) + int64(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextIntArray(size int) []int {
	return io.NextIntArrayOffset(size, 0)
}

func (io *FastIO) NextIntArrayOffset(size, offset int) []int {
	arr := make([]int, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextInt()
	}
	return arr
}

func (io *FastIO) NextLongArray(size int) []int64 {
	return io.NextLongArrayOffset(size, 0)
}

func (io *FastIO) NextLongArrayOffset(size, offset int) []int64 {
	arr := make([]int64, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextLong()
	}
	return arr
}

func (io *FastIO) NextString() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsSpaceChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) NextLine() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsLineBreakChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) Println(args ...interface{}) {
	io.writer.WriteString(fmt.Sprintln(args...))
}

func (io *FastIO) Printf(format string, args ...interface{}) {
	io.writer.WriteString(fmt.Sprintf(format, args...))
}

func (io *FastIO) FlushOutput() {
	io.writer.Flush()
}

func IsSpaceChar(c byte) bool {
	switch c {
	case 0, '\t', '\n', '\r', ' ':
		return true
	default:
		return false
	}
}

func IsLineBreakChar(c byte) bool {
	switch c {
		case 0, '\n', '\r':
			return true
		default:
			return false
	}
}

func main() {
	io := FastIO{reader: bufio.NewReader(os.Stdin), writer: bufio.NewWriter(os.Stdout)}
	Init()
	Solve(&io)
	io.FlushOutput()
}

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
)

func Init() {
}

func Solve(io *FastIO) {
	N := io.NextInt()
	M := io.NextInt()
	Q := io.NextInt()

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

	for i := 0; i < M; i++ {
	  A := io.NextInt()
	  B := io.NextInt()

	  nodes[A].next = append(nodes[A].next, nodes[B])
	  nodes[B].next = append(nodes[B].next, nodes[A])
	}

	seen := make([]bool, N + 1)
	diam := make([]int, N + 1)
	djs := NewDisjointSet(N + 1)
	for i := 1; i <= N; i++ {
	  if seen[i] {
	    continue
	  }
	  cmp := GetComponent(nodes[i])
	  root, _ := FarthestNode(cmp[0], nil)
	  _, dist := FarthestNode(root, nil)
	  for _, u := range cmp {
	    seen[u.id] = true
	  }
	  for j := 1; j < len(cmp); j++ {
	    djs.union(cmp[0].id, cmp[j].id)
	  }
	  part := djs.find(cmp[0].id)
	  diam[part] = dist
	}

	for q := 0; q < Q; q++ {
	  T := io.NextInt()

	  switch T {
	    case 1: {
	      X := io.NextInt()

	      part := djs.find(X)
	      io.Println(diam[part])
	    }
	    case 2: {
	      X := io.NextInt()
	      Y := io.NextInt()

	      partX := djs.find(X)
	      partY := djs.find(Y)
	      if partX != partY {
	        dx := diam[partX]
	        dy := diam[partY]
	        dist := 1 + ((dx + 1) >> 1) + ((dy + 1) >> 1)
	        djs.union(X, Y)
	        part := djs.find(X)
	        diam[part] = dist
	      }
	    }
	  }
	}
}

type Node struct {
  next []*Node
  id int
}

func NewNode(i int) *Node {
  return &Node{
    id: i,
    next: make([]*Node, 0),
  }
}

func FarthestNode(u, p *Node) (*Node, int) {
  far := u
  dist := 0
  for _, v := range u.next {
    if v == p {
      continue
    }
    f, d := FarthestNode(v, u)
    if d >= dist {
      far = f
      dist = d + 1
    }
  }
  return far, dist
}

func componentHelper(u *Node, seen map[*Node]bool) {
  seen[u] = true
  for _, v := range u.next {
    if !seen[v] {
      componentHelper(v, seen)
    }
  }
}

func GetComponent(u *Node) []*Node {
  seen := make(map[*Node]bool)
  componentHelper(u, seen)
  comp := make([]*Node, 0, len(seen))
  for u := range seen {
    comp = append(comp, u)
  }
  return comp
}

type DisjointSet struct {
	parent []int
	rank []int
}

func NewDisjointSet(n int) *DisjointSet {
	dj := DisjointSet{
		parent: make([]int, n),
		rank: make([]int, n),
	}
	for i := 0; i < n; i++ {
		dj.parent[i] = i
	}
	return &dj
}

func (dj *DisjointSet) find(x int) int {
	if dj.parent[x] != x {
		dj.parent[x] = dj.find(dj.parent[x])
	}
	return dj.parent[x]
}

func (dj *DisjointSet) union(x, y int) bool {
	xr := dj.find(x)
	yr := dj.find(y)

	if xr == yr {
		return false
	}

	if dj.rank[xr] < dj.rank[yr] {
		dj.parent[xr] = yr
	} else if dj.rank[xr] > dj.rank[yr] {
		dj.parent[yr] = xr
	} else {
		dj.parent[xr] = yr
		dj.rank[yr]++
	}
	return true
}

type FastIO struct {
	reader *bufio.Reader
	writer *bufio.Writer
}

func (io *FastIO) NextChar() byte {
	c, _ := io.reader.ReadByte()
	return c
}

func (io *FastIO) NextInt() int {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := 1
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := 0
	for !IsSpaceChar(c) {
		res = (res * 10) + int(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextLong() int64 {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := int64(1)
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := int64(0)
	for !IsSpaceChar(c) {
		res = (res * 10) + int64(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextIntArray(size int) []int {
	return io.NextIntArrayOffset(size, 0)
}

func (io *FastIO) NextIntArrayOffset(size, offset int) []int {
	arr := make([]int, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextInt()
	}
	return arr
}

func (io *FastIO) NextLongArray(size int) []int64 {
	return io.NextLongArrayOffset(size, 0)
}

func (io *FastIO) NextLongArrayOffset(size, offset int) []int64 {
	arr := make([]int64, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextLong()
	}
	return arr
}

func (io *FastIO) NextString() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsSpaceChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) NextLine() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsLineBreakChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) Println(args ...interface{}) {
	io.writer.WriteString(fmt.Sprintln(args...))
}

func (io *FastIO) Printf(format string, args ...interface{}) {
	io.writer.WriteString(fmt.Sprintf(format, args...))
}

func (io *FastIO) FlushOutput() {
	io.writer.Flush()
}

func IsSpaceChar(c byte) bool {
	switch c {
	case 0, '\t', '\n', '\r', ' ':
		return true
	default:
		return false
	}
}

func IsLineBreakChar(c byte) bool {
	switch c {
		case 0, '\n', '\r':
			return true
		default:
			return false
	}
}

func main() {
	io := FastIO{reader: bufio.NewReader(os.Stdin), writer: bufio.NewWriter(os.Stdout)}
	Init()
	Solve(&io)
	io.FlushOutput()
}

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
)

func Init() {
}

func Solve(io *FastIO) {
	N := io.NextInt()
	M := io.NextInt()
	Q := io.NextInt()

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

	for i := 0; i < M; i++ {
	  A := io.NextInt()
	  B := io.NextInt()

	  nodes[A].next = append(nodes[A].next, nodes[B])
	  nodes[B].next = append(nodes[B].next, nodes[A])
	}

	seen := make([]bool, N + 1)
	diam := make([]int, N + 1)
	djs := NewDisjointSet(N + 1)
	for i := 1; i <= N; i++ {
	  if seen[i] {
	    continue
	  }
	  cmp := GetComponent(nodes[i])
	  root, _ := FarthestNode(cmp[0], nil)
	  _, dist := FarthestNode(root, nil)
	  for _, u := range cmp {
	    seen[u.id] = true
	  }
	  for j := 1; j < len(cmp); j++ {
	    djs.union(cmp[0].id, cmp[j].id)
	  }
	  part := djs.find(cmp[0].id)
	  diam[part] = dist
	}

	for q := 0; q < Q; q++ {
	  T := io.NextInt()

	  fmt.Println(q)

	  switch T {
	    case 1: {
	      X := io.NextInt()

	      part := djs.find(X)
	      io.Println(diam[part])
	    }
	    case 2: {
	      X := io.NextInt()
	      Y := io.NextInt()

	      partX := djs.find(X)
	      partY := djs.find(Y)
	      if partX != partY {
	        dx := diam[partX]
	        dy := diam[partY]
	        dist := 1 + ((dx + 1) >> 1) + ((dy + 1) >> 1)
	        djs.union(X, Y)
	        part := djs.find(X)
	        diam[part] = dist
	      }
	    }
	  }
	}
}

type Node struct {
  next []*Node
  id int
}

func NewNode(i int) *Node {
  return &Node{
    id: i,
    next: make([]*Node, 0),
  }
}

func FarthestNode(u, p *Node) (*Node, int) {
  far := u
  dist := 0
  for _, v := range u.next {
    if v == p {
      continue
    }
    f, d := FarthestNode(v, u)
    if d >= dist {
      far = f
      dist = d + 1
    }
  }
  return far, dist
}

func componentHelper(u *Node, seen map[*Node]bool) {
  seen[u] = true
  for _, v := range u.next {
    if !seen[v] {
      componentHelper(v, seen)
    }
  }
}

func GetComponent(u *Node) []*Node {
  seen := make(map[*Node]bool)
  componentHelper(u, seen)
  comp := make([]*Node, 0, len(seen))
  for u := range seen {
    comp = append(comp, u)
  }
  return comp
}

type DisjointSet struct {
	parent []int
	rank []int
}

func NewDisjointSet(n int) *DisjointSet {
	dj := DisjointSet{
		parent: make([]int, n),
		rank: make([]int, n),
	}
	for i := 0; i < n; i++ {
		dj.parent[i] = i
	}
	return &dj
}

func (dj *DisjointSet) find(x int) int {
	if dj.parent[x] != x {
		dj.parent[x] = dj.find(dj.parent[x])
	}
	return dj.parent[x]
}

func (dj *DisjointSet) union(x, y int) bool {
	xr := dj.find(x)
	yr := dj.find(y)

	if xr == yr {
		return false
	}

	if dj.rank[xr] < dj.rank[yr] {
		dj.parent[xr] = yr
	} else if dj.rank[xr] > dj.rank[yr] {
		dj.parent[yr] = xr
	} else {
		dj.parent[xr] = yr
		dj.rank[yr]++
	}
	return true
}

type FastIO struct {
	reader *bufio.Reader
	writer *bufio.Writer
}

func (io *FastIO) NextChar() byte {
	c, _ := io.reader.ReadByte()
	return c
}

func (io *FastIO) NextInt() int {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := 1
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := 0
	for !IsSpaceChar(c) {
		res = (res * 10) + int(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextLong() int64 {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := int64(1)
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := int64(0)
	for !IsSpaceChar(c) {
		res = (res * 10) + int64(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextIntArray(size int) []int {
	return io.NextIntArrayOffset(size, 0)
}

func (io *FastIO) NextIntArrayOffset(size, offset int) []int {
	arr := make([]int, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextInt()
	}
	return arr
}

func (io *FastIO) NextLongArray(size int) []int64 {
	return io.NextLongArrayOffset(size, 0)
}

func (io *FastIO) NextLongArrayOffset(size, offset int) []int64 {
	arr := make([]int64, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextLong()
	}
	return arr
}

func (io *FastIO) NextString() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsSpaceChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) NextLine() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsLineBreakChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) Println(args ...interface{}) {
	io.writer.WriteString(fmt.Sprintln(args...))
}

func (io *FastIO) Printf(format string, args ...interface{}) {
	io.writer.WriteString(fmt.Sprintf(format, args...))
}

func (io *FastIO) FlushOutput() {
	io.writer.Flush()
}

func IsSpaceChar(c byte) bool {
	switch c {
	case 0, '\t', '\n', '\r', ' ':
		return true
	default:
		return false
	}
}

func IsLineBreakChar(c byte) bool {
	switch c {
		case 0, '\n', '\r':
			return true
		default:
			return false
	}
}

func main() {
	io := FastIO{reader: bufio.NewReader(os.Stdin), writer: bufio.NewWriter(os.Stdout)}
	Init()
	Solve(&io)
	io.FlushOutput()
}

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
)

func Init() {
}

func Solve(io *FastIO) {
  N := io.NextInt()

  zero := 0
  one := 1023

  for i := 0; i < N; i++ {
    OP := io.NextString()
    X := io.NextInt()

    switch OP {
      case "&":
        zero &= X
        one &= X
      case "|":
        zero |= X
        one |= X
      case "^":
        zero ^= X
        one ^= X
    }
  }

  and := 1023
  or := 0
  xor := 0

  for i := uint(0); i < 10; i++ {
    b0 := (zero >> i) & 1
    b1 := (one >> i) & 1
    b := (1 << i)
    if b0 == 0 && b1 == 0 {
      and ^= b
    } else if b0 == 1 && b1 == 1 {
      or ^= b
    } else if b0 != 0 && b1 != 1 {
      xor ^= b
    }
  }

  io.Println(3)
  io.Printf("& %d\n", and)
  io.Printf("| %d\n", or)
  io.Printf("^ %d\n", xor)
}

type FastIO struct {
	reader *bufio.Reader
	writer *bufio.Writer
}

func (io *FastIO) NextChar() byte {
	c, _ := io.reader.ReadByte()
	return c
}

func (io *FastIO) NextInt() int {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := 1
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := 0
	for !IsSpaceChar(c) {
		res = (res * 10) + int(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextLong() int64 {
	c := io.NextChar()
	for IsSpaceChar(c) {
		c = io.NextChar()
	}
	sgn := int64(1)
	if c == '-' {
		sgn = -1
		c = io.NextChar()
	}
	res := int64(0)
	for !IsSpaceChar(c) {
		res = (res * 10) + int64(c - '0')
		c = io.NextChar()
	}
	return sgn * res
}

func (io *FastIO) NextIntArray(size int) []int {
	return io.NextIntArrayOffset(size, 0)
}

func (io *FastIO) NextIntArrayOffset(size, offset int) []int {
	arr := make([]int, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextInt()
	}
	return arr
}

func (io *FastIO) NextLongArray(size int) []int64 {
	return io.NextLongArrayOffset(size, 0)
}

func (io *FastIO) NextLongArrayOffset(size, offset int) []int64 {
	arr := make([]int64, size + offset)
	for i := 0; i < size; i++ {
		arr[i + offset] = io.NextLong()
	}
	return arr
}

func (io *FastIO) NextString() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsSpaceChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) NextLine() string {
	c := io.NextChar()
	for (IsSpaceChar(c)) {
		c = io.NextChar()
	}
	var sb bytes.Buffer
	for !IsLineBreakChar(c) {
		sb.WriteByte(c)
		c = io.NextChar()
	}
	return sb.String()
}

func (io *FastIO) Println(args ...interface{}) {
	io.writer.WriteString(fmt.Sprintln(args...))
}

func (io *FastIO) Printf(format string, args ...interface{}) {
	io.writer.WriteString(fmt.Sprintf(format, args...))
}

func (io *FastIO) FlushOutput() {
	io.writer.Flush()
}

func IsSpaceChar(c byte) bool {
	switch c {
	case 0, '\t', '\n', '\r', ' ':
		return true
	default:
		return false
	}
}

func IsLineBreakChar(c byte) bool {
	switch c {
		case 0, '\n', '\r':
			return true
		default:
			return false
	}
}

func main() {
	io := FastIO{reader: bufio.NewReader(os.Stdin), writer: bufio.NewWriter(os.Stdout)}
	Init()
	Solve(&io)
	io.FlushOutput()
}


// 381B-mic
package main

import (
    "fmt"
)

func main() {
    var s [100001]int
    var l [100001]int
    var r [100001]int
    var n, b int
    max := -1
    c := 0
    fmt.Scan(&n)
    for i := 0; i < n; i++ {
        fmt.Scan(&b)
        if s[b] < 2 {
            s[b]++
            c++
        }
        if b > max {
            max = b
        }
    }
    for i := 1; i < 100001; i++ {
        if s[i] == 2 {
            l[i]++
            r[i]++
        }
        if s[i] == 1 {
            l[i]++
        }
    }
    if s[max] > 1 {
        c--
    }
    fmt.Println(c)
    for i := 1; i < max; i++ {
        if l[i] == 1 {
            fmt.Print(i)
            fmt.Print(" ")
        }

    }
    fmt.Print(max)
    fmt.Print(" ")
    for i := max - 1; i >= 1; i-- {
        if r[i] == 1 {
            fmt.Print(i)
            fmt.Print(" ")
        }
    }
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scan(&n)
	card := make([]int, n)
	for i := 0; i < n; i++ {
		fmt.Scan(&card[i])
	}

	sort.Ints(card)
	var table []int
	var rest []int
	for _, v := range card {
		if len(table) == 0 || v != table[len(table)-1] {
			table = append(table, v)
		} else {
			rest = append(rest, v)
		}
	}

	for i := len(rest)-1; i >= 0; i-- {
		if rest[i] != table[len(table)-1] {
			table = append(table, rest[i])
		}
	}

	fmt.Println(len(table))
	for _, v := range table {
		fmt.Print(v, " ")
	}
	fmt.Println()
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scanln(&n)
	a := make([]int, n)
	for i := 0; i < n; i++ {
		fmt.Scanf("%d", &a[i])
	}
	sort.Ints(a)
	var max int = a[n-1]
	fi := make([]int, 0, n)
	se := make([]int, 0, n)
	var pf, ps int = max, max
	for i := n - 1; i >= 0; i-- {
		if a[i] < pf {
			fi = append(fi, a[i])
			pf = a[i]
		} else if a[i] < ps {
			se = append(se, a[i])
			ps = a[i]
		}
	}
	var len_fi, len_se int = len(fi), len(se)
	fmt.Println(len_fi + len_se + 1)
	for i := len_fi - 1; i >= 0; i-- {
		fmt.Printf("%d ", fi[i])
	}
	fmt.Printf("%d", max)
	for i := 0; i < len_se; i++ {
		fmt.Printf(" %d", se[i])
	}
	fmt.Println()
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scanln(&n)
	a := make([]int, n)
	for i := 0; i < n; i++ {
		fmt.Scanf("%d", &a[i])
	}
	sort.Ints(a)
	var max int = a[n-1]
	var fi, se []int
	var pf, ps int = max, max
	for i := n - 1; i >= 0; i-- {
		if a[i] < pf {
			fi = append(fi, a[i])
			pf = a[i]
		} else if a[i] < ps {
			se = append(se, a[i])
			ps = a[i]
		}
	}
	var len_fi, len_se int = len(fi), len(se)
	fmt.Println(len_fi + len_se + 1)
	for i := len_fi - 1; i >= 0; i-- {
		fmt.Printf("%d ", fi[i])
	}
	fmt.Printf("%d", max)
	for i := 0; i < len_se; i++ {
		fmt.Printf(" %d", se[i])
	}
	fmt.Println()
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scan(&n)
	card := make([]int, n);

	for i:=0; i<n; i++ {
		fmt.Scan(&card[i])
	}

	if !sort.IntsAreSorted(card) {
		sort.Ints(card)
	}
	// sort.Ints(card)

	stairs := make([]int, 1, n+1)

	stairs[0] = card[n-1]

	for i, j:=n-2, 0; i>=0; i-- {
		if card[i]<stairs[j] {
			stairs = append(stairs, card[i])
			j++
			card[i]=0
		}
	}

	max := stairs[0]
	// fmt.Println(stairs, len(stairs), cap(stairs))

	// stairsTemp := stairs[len(stairs): len(stairs)+1]
	stairsTemp := make([]int, 1, n)
	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))
	// fmt.Println(card, max)

	for i:=0; i<n; i++ {
		if card[i] != 0 {
			stairsTemp[0]=card[i];
			break;
		}
	}

	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))

	if stairsTemp[0]!=0 && stairsTemp[0]!=max {
		for i, j:=0, 0; card[i]<max; i++ {
			if card[i]>stairsTemp[j] {
				stairsTemp = append(stairsTemp, card[i])
				j++
			}
		}
		stairs = append(stairsTemp, stairs...)
	}

	fmt.Println(len(stairs))
	for _, v := range stairs {
		fmt.Printf("%d ", v)
	}
	fmt.Println("")
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scanln(&n)
	card := make([]int, n);

	for i:=0; i<n; i++ {
		fmt.Scanf("%d", &card[i])
	}

	// if !sort.IntsAreSorted(card) {
	// 	sort.Ints(card)
	// }
		sort.Ints(card)

	stairs := make([]int, 1, n)

	stairs[0] = card[n-1]

	for i, j:=n-2, 0; i>=0; i-- {
		if card[i]<stairs[j] {
			stairs = append(stairs, card[i])
			j++
			card[i]=0
		}
	}

	max := stairs[0]
	// fmt.Println(stairs, len(stairs), cap(stairs))
	// stairsTemp := stairs[len(stairs): cap(stairs)]
	stairsTemp := make([]int, 1, n)
	for i:=0; i<n; i++ {
		if card[i] != 0 {
			stairsTemp[0]=card[i];
			break;
		}
	}
	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))

	if stairsTemp[0]!=0 && stairsTemp[0]!=max {
		for i, j:=0, 0; card[i]<max; i++ {
			if card[i]>stairsTemp[j] {
				stairsTemp = append(stairsTemp, card[i])
				j++
			}
		}
		stairs = append(stairsTemp, stairs...)
	}

	fmt.Println(len(stairs))
	for _, v := range stairs {
		fmt.Printf("%d ", v)
	}
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scanln(&n)
	card := make([]int, n);

	for i:=0; i<n; i++ {
		fmt.Scanf("%d", &card[i])
	}

	if !sort.IntsAreSorted(card) {
		sort.Ints(card)
	}

	stairs := make([]int, 1, n)

	stairs[0] = card[n-1]

	for i, j:=n-2, 0; i>=0; i-- {
		if card[i]<stairs[j] {
			stairs = append(stairs, card[i])
			j++
			card[i]=0
		}
	}

	max := stairs[0]
	stairsTemp := make([]int, 1, n)
	for i:=0; i<n; i++ {
		if card[i] != 0 {
			stairsTemp[0]=card[i];
			break;
		}
	}

	if stairsTemp[0]!=0 && stairsTemp[0]!=max {
		for i, j:=0, 0; card[i]<max; i++ {
			if card[i]>stairsTemp[j] {
				stairsTemp = append(stairsTemp, card[i])
				j++
			}
		}
		stairs = append(stairsTemp, stairs...)
	}

	fmt.Println(len(stairs))
	for _, v := range stairs {
		fmt.Printf("%d ", v)
	}
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scan(&n)
	card := make([]int, n);

	for i:=0; i<n; i++ {
		fmt.Scan(&card[i])
	}

	// if !sort.IntsAreSorted(card) {
	// 	sort.Ints(card)
	// }
	sort.Ints(card)

	stairs := make([]int, 1, n+1)

	stairs[0] = card[n-1]

	for i, j:=n-2, 0; i>=0; i-- {
		if card[i]<stairs[j] {
			stairs = append(stairs, card[i])
			j++
			card[i]=0
		}
	}

	max := stairs[0]
	// fmt.Println(stairs, len(stairs), cap(stairs))

	stairsTemp := stairs[len(stairs): len(stairs)+1]
	// stairsTemp := make([]int, 1, n)
	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))
	// fmt.Println(card, max)

	for i:=0; i<n; i++ {
		if card[i] != 0 {
			stairsTemp[0]=card[i];
			break;
		}
	}

	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))

	if stairsTemp[0]!=0 && stairsTemp[0]!=max {
		for i, j:=0, 0; card[i]<max; i++ {
			if card[i]>stairsTemp[j] {
				stairsTemp = append(stairsTemp, card[i])
				j++
			}
		}
		stairs = append(stairsTemp, stairs...)
	}

	fmt.Println(len(stairs))
	for _, v := range stairs {
		fmt.Printf("%d ", v)
	}
	fmt.Println("")
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scan(&n)
	card := make([]int, n);

	for i:=0; i<n; i++ {
		fmt.Scan(&card[i])
	}

	if !sort.IntsAreSorted(card) {
		sort.Ints(card)
	}
	// sort.Ints(card)

	stairs := make([]int, 1, n+1)

	stairs[0] = card[n-1]

	for i, j:=n-2, 0; i>=0; i-- {
		if card[i]<stairs[j] {
			stairs = append(stairs, card[i])
			j++
			card[i]=0
		}
	}

	max := stairs[0]
	// fmt.Println(stairs, len(stairs), cap(stairs))

	stairsTemp := stairs[len(stairs): len(stairs)+1]
	// stairsTemp := make([]int, 1, n)
	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))
	// fmt.Println(card, max)

	for i:=0; i<n; i++ {
		if card[i] != 0 {
			stairsTemp[0]=card[i];
			break;
		}
	}

	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))

	if stairsTemp[0]!=0 && stairsTemp[0]!=max {
		for i, j:=0, 0; card[i]<max; i++ {
			if card[i]>stairsTemp[j] {
				stairsTemp = append(stairsTemp, card[i])
				j++
			}
		}
		stairs = append(stairsTemp, stairs...)
	}

	fmt.Println(len(stairs))
	for _, v := range stairs {
		fmt.Printf("%d ", v)
	}
	fmt.Println("")
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scan(&n)
	card := make([]int, n);

	for i:=0; i<n; i++ {
		fmt.Scan(&card[i])
	}

	if !sort.IntsAreSorted(card) {
		sort.Ints(card)
	}
	// sort.Ints(card)

	stairs := make([]int, 1, n+1)

	stairs[0] = card[n-1]

	for i, j:=n-2, 0; i>=0; i-- {
		if card[i]<stairs[j] {
			stairs = append(stairs, card[i])
			j++
			card[i]=0
		}
	}

	max := stairs[0]
	// fmt.Println(stairs, len(stairs), cap(stairs))

	// stairsTemp := stairs[len(stairs): len(stairs)+1]
	stairsTemp := make([]int, 1, n)
	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))
	// fmt.Println(card, max)

	for i:=0; i<n; i++ {
		if card[i] != 0 {
			stairsTemp[0]=card[i];
			break;
		}
	}

	// fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))

	if stairsTemp[0]!=0 && stairsTemp[0]!=max {
		for i, j:=0, 0; card[i]<max; i++ {
			if card[i]>stairsTemp[j] {
				stairsTemp = append(stairsTemp, card[i])
				j++
			}
		}
		stairs = append(stairsTemp, stairs...)
	}

	fmt.Println(len(stairs))
	for _, v := range stairs {
		fmt.Printf("%d ", v)
	}
	// fmt.Println("")
}

package main
import (
	"fmt"
	"bufio"
	"os"
	"strconv"
)

func main() {
	var m,x,s,t,i int
	a:=make([]int,5002)
	fmt.Scan(&m)
	input:= bufio.NewScanner(os.Stdin)
	input.Split(bufio.ScanWords)
	s=0
	for i:=0;i<m;i++ {
		input.Scan()
		aa,_:= strconv.Atoi(input.Text())
		x=aa
		a[x]++
		if x>s {
			s=x
		}
	}
	for i=1;i<s;i++ {
		if a[i]>1 {
			t+=2
		} else if a[i]==1 {
			t++
		}
	}
	fmt.Println(t+1)
	for i=1;i<=s;i++ {
		if a[i]!=0 {
			fmt.Print(i," ")
			a[i]--
		}
	}
	for i=s-1;i>0;i-- {
		if a[i]!=0 {
			fmt.Print(i," ")
		}
	}
	fmt.Println()
}

package main

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

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    scanner.Split(bufio.ScanWords)
    var m int
    var f [5001]int
    fmt.Scan(&m)
    for i := 0; i < m; i++ {
        scanner.Scan()
        a, _ := strconv.Atoi(scanner.Text())
        f[a]++
    }
    first, cnt, mid, ans := true, 0, 0, ""
    for i := 1; i <= 5000; i++ {
        if f[i] > 0 {
            if first { first = false } else { ans += " " }
            ans += strconv.Itoa(i)
            cnt++
            f[i]--
            mid = i
        }
    }
    for i := mid-1; i >= 1; i-- {
        if f[i] > 0 {
            ans += " "
            ans += strconv.Itoa(i)
            cnt++
            f[i]--
        }
    }
    fmt.Println(cnt)
    fmt.Println(ans)
}

package main

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

func main() {
    scanner := bufio.NewScanner(os.Stdin)    			// fungsi bufio
    scanner.Split(bufio.ScanWords)
    var m int											// membuat variabel m dengan jenis int
    var f [5001]int										// membuat variabel f [5001] dengan jenis int
    fmt.Scan(&m)										// mengambil input
    for i := 0; i < m; i++ {							// looping
        scanner.Scan()								  // mengambil input kedua
        a, _ := strconv.Atoi(scanner.Text())			// mengubah string menjadi integer
        f[a]++											//f[a] ditambah terus
    }
    first, cnt, mid, ans := true, 0, 0, ""			// membuat variabel first,cnt,mid,ans yang diisi dengan true,0,0 dan ""
    for i := 1; i <= 5000; i++ {					// looping kedua
        if f[i] > 0 {									// jika f[i] lebih dari 0,maka
            if first { first = false } else { ans += " " }  // jika first maka first sama dengan false, lainnya ans ditambah spasi
            ans += strconv.Itoa(i)				// ans ditambah i yang diubah dari int menjadi string
            cnt++									// cnt ditambah terus
            f[i]--									//f[i] dikurang terus
            mid = i									// mid sama dengan i
        }
    }
    for i := mid-1; i >= 1; i-- {					// looping ke 3
        if f[i] > 0 {								// jika f[i] lebih dari 0
            ans += " "								// ans ditambah spasi
            ans += strconv.Itoa(i)					// ans ditambah i yang diubah dari int menjadi string
            cnt++									// cnt ditambah terus
            f[i]--									// f[i] dikurang terus
        }
    }
    fmt.Println(cnt)							// cetak hasil cnt
    fmt.Println(ans)							// cetak hasil ans
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scanln(&n)
	card := make([]int, n);

	for i:=0; i<n; i++ {
		fmt.Scanf("%d", &card[i])
	}

	if !sort.IntsAreSorted(card) {
		sort.Ints(card)
	}

	stairs := make([]int, 1, n)

	stairs[0] = card[n-1]

	for i, j:=n-2, 0; i>=0; i-- {
		if card[i]<stairs[j] {
			stairs = append(stairs, card[i])
			j++
			card[i]=0
		}
	}

	max := stairs[0]
	fmt.Println(stairs, len(stairs), cap(stairs))
	// stairsTemp := stairs[len(stairs): cap(stairs)]
	stairsTemp := make([]int, 1, n)
	for i:=0; i<n; i++ {
		if card[i] != 0 {
			stairsTemp[0]=card[i];
			break;
		}
	}
	fmt.Println(stairsTemp, len(stairsTemp), cap(stairsTemp))

	if stairsTemp[0]!=0 && stairsTemp[0]!=max {
		for i, j:=0, 0; card[i]<max; i++ {
			if card[i]>stairsTemp[j] {
				stairsTemp = append(stairsTemp, card[i])
				j++
			}
		}
		stairs = append(stairsTemp, stairs...)
	}

	fmt.Println(len(stairs))
	for _, v := range stairs {
		fmt.Printf("%d ", v)
	}
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scanln(&n)
	card := make([]int, n);

	for i:=0; i<n; i++ {
		fmt.Scanf("%d", &card[i])
	}

	if !sort.IntsAreSorted(card) {
		sort.Ints(card)
	}

	stairs := make([]int, 1, n)

	stairs[0] = card[n-1]

	for i, j:=n-2, 0; i>=0; i-- {
		if card[i]<stairs[j] {
			stairs = append(stairs, card[i])
			j++
			card[i]=0
		}
	}

	max := stairs[0]
	stairsTemp := make([]int, 1, n)
	for i:=0; i<n; i++ {
		if card[i] != 0 {
			stairsTemp[0]=card[i];
			break;
		}
	}

	if stairsTemp[0]!=0 && stairsTemp[0]!=max {
		for i, j:=0, 0; card[i]<max; i++ {
			if card[i]>stairsTemp[j] {
				stairsTemp = append(stairsTemp, card[i])
				j++
			}
		}
		stairs = append(stairsTemp, stairs...)
	}

	fmt.Println(len(stairs))
	fmt.Println(stairs)
}

package main

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

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    scanner.Split(bufio.ScanWords)
    writer := bufio.NewWriter(os.Stdout)
    var m int
    var f [5001]int
    fmt.Scan(&m)
    for i := 0; i < m; i++ {
        scanner.Scan()
        a, _ := strconv.Atoi(scanner.Text())
        f[a]++
    }
    first, cnt, mid := true, 0, 0
    for i := 1; i <= 5000; i++ {
        if f[i] > 0 {
            if first { first = false } else { writer.WriteRune(' ') }
            writer.WriteString(strconv.Itoa(i))
            cnt++
            f[i]--
            mid = i
        }
    }
    for i := mid-1; i >= 1; i-- {
        if f[i] > 0 {
            writer.WriteRune(' ')
            writer.WriteString(strconv.Itoa(i))
            cnt++
            f[i]--
        }
    }
    writer.WriteRune('\n')
    fmt.Println(cnt)
    writer.Flush()
}

// 381B-mic
package main

import (
    "fmt"
)

func main() {
    var s [100001]int
    var l [100001]int
    var r [100001]int
    var n, b int
    max := -1
    c := 0

    fmt.Scan(&n)
    for i := 0; i < n; i++ {

        fmt.Scan(&b)
        if s[b] < 2 {
            s[b]++
            c++
        }
        if b > max {
            max = b
        }
    }
    for i := 1; i < 100001; i++ {
        if s[i] == 2 {
            l[i]++
            r[i]++
        }
        if s[i] == 1 {
            l[i]++
        }
    }
    if s[max] > 1 {
        c--
        fmt.Println(c)
    }
    for i := 1; i < max; i++ {
        if l[i] == 1 {
            fmt.Print(i)
            fmt.Print(" ")
        }

    }
    fmt.Print(max)
    fmt.Print(" ")
    for i := max - 1; i >= 1; i-- {
        if r[i] == 1 {
            fmt.Print(i)
            fmt.Print(" ")
        }
    }
}

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scan(&n)
	card := make([]int, n)
	for i := 0; i < n; i++ {
		fmt.Scan(&card[i])
	}

	sort.Ints(card)
	var table []int
	var rest []int
	for _, v := range card {
		if len(table) == 0 || v != table[len(table)-1] {
			table = append(table, v)
		} else {
			rest = append(rest, v)
		}
	}

	for i := len(rest)-1; i >= 0; i-- {
		if rest[i] != table[len(table)-1] {
			table = append(table, rest[i])
		}
	}

	for _, v := range table {
		fmt.Print(v, " ")
	}
	fmt.Println()
}