Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], skipTags: ["script","noscript","style","textarea","code"], processEscapes: true }});

Tree Separator

You are given a tree $T$ and an integer $K$. You can choose arbitrary distinct two vertices $u$ and $v$ on $T$. Let $P$ be the simple path between $u$ and $v$. Then, remove vertices in $P$, and edges such that one or both of its end vertices is in $P$ from $T$. Your task is to choose $u$ and $v$ to maximize the number of connected components with $K$ or more vertices of $T$ after that operation.

Input

The input consists of a single test case formatted as follows.

$N$ $K$
$u_1$ $v_1$
:
$u_{N-1}$ $v_{N-1}$

The first line consists of two integers $N, K$ ($2 \leq N \leq 100,000, 1 \leq K \leq N$). The following $N-1$ lines represent the information of edges. The ($i+1$)-th line consists of two integers $u_i, v_i$ ($1 \leq u_i, v_i \leq N$ and $u_i \ne v_i $ for each $i$). Each $\{u_i, v_i\}$ is an edge of $T$. It's guaranteed that these edges form a tree.

Output

Print the maximum number of connected components with $K$ or more vertices in one line.

Sample Input 1

2 1
1 2

Output for Sample Input 1

0

Sample Input 2

7 3
1 2
2 3
3 4
4 5
5 6
6 7

Output for Sample Input 2

1

Sample Input 3

12 2
1 2
2 3
3 4
4 5
3 6
6 7
7 8
8 9
6 10
10 11
11 12

Output for Sample Input 3

4

Sample Input 4

3 1
1 2
2 3

Output for Sample Input 4

1

Sample Input 5

3 2
1 2
2 3

Output for Sample Input 5

0

Sample Input 6

9 3
1 2
1 3
1 4
4 5
4 6
4 7
7 8
7 9

Output for Sample Input 6

2

Solution in Scala (judge verdict: Accepted)

object Main extends App {

  import scala.io.StdIn._
  val Array(n, k) = readLine.trim.split(' ').map(_.toInt)
  val nodes = Array.tabulate(n){_ ⇒ new Node}
  for (_ ← 1 until n){
    val Array(u, v) = readLine.trim.split(' ').map(_.toInt)
    nodes(u - 1).addEdge(nodes(v - 1))
    nodes(v - 1).addEdge(nodes(u - 1))
  }
  countSubTree(nodes(0), k, n)
  val filtered = nodes.filter(_.subTreeOverKCount >= 3)
  println(filtered.length match {
    case 0 ⇒ {
      nodes.find(_.subTreeOverKCount == 2) match {
        case Some(_) if n >= k * 2 + 2 ⇒ 2
        case Some(_) ⇒ 1
        case None ⇒ nodes.find(_.subTreeOverKCount == 1) match {
          case Some(_) if n >= k + 2 ⇒ 1
          case _ ⇒ 0
        }
      }
    }
    case 1 ⇒ {
      val node = nodes.find(_.subTreeOverKCount >= 3).get
      nodes.find(_.subTreeOverKCount == 2) match {
        case Some(_) ⇒ node.subTreeOverKCount
        case None if node.edges.size > node.subTreeOverKCount ⇒ node.subTreeOverKCount
        case _ ⇒ node.subTreeOverKCount - 1
      }
    }
    case _ ⇒ {
      val subRoot = (new Node).also(_.subTreeOverKCount = filtered(0).subTreeOverKCount)
      filtered(0).edges.foreach(makeSubTree(_, filtered(0), subRoot))
      calMaxPath(subRoot)
    }
  })
  def countSubTree(node: Node, k: Int, n: Int): Unit = {
    node.subTreeOverKCount = node.edges.count(next ⇒ countSubTree(next, node, k, n) >= k)
  }
  def countSubTree(node: Node, parent: Node, k: Int, n: Int): Int = {
    node.edges.filter(_ != parent).map{next ⇒
      countSubTree(next, node, k, n)
    }.let{children ⇒
      node.subTreeOverKCount = children.count(_ >= k)
      val sum = children.sum + 1
      if (n - sum >= k) node.subTreeOverKCount += 1
      sum
    }
  }
  def makeSubTree(current: Node, parent: Node, subTree: Node): Unit = {
    if (current.subTreeOverKCount >= 3){
      val next = new Node
      next.subTreeOverKCount = current.subTreeOverKCount
      subTree.addEdge(next)
      next.addEdge(subTree)
      current.edges.withFilter(_ != parent).foreach(n ⇒ makeSubTree(n, current, next))
    }else{
      current.edges.withFilter(_ != parent).foreach(n ⇒ makeSubTree(n, current, subTree))
    }
  }
  def calMaxPath(root: Node): Int = {
    calMaxPath(root, new Node)._2 + 2
  }
  def calMaxPath(node: Node, parent: Node): (Int, Int) = {
    val filtered = node.edges.filter(_ != parent)
    if (filtered.isEmpty){
      (node.subTreeOverKCount - 2, node.subTreeOverKCount - 2)
    }else if (filtered.size == 1){
      val (path, res) = calMaxPath(filtered.head, node)
      if (path + node.subTreeOverKCount - 2 > res) (path + node.subTreeOverKCount - 2, path + node.subTreeOverKCount - 2)
      else (path + node.subTreeOverKCount - 2, res)
    }else {
      val mapped = filtered.map(calMaxPath(_, node))
      val sorted = mapped.map(_._1).toList.sorted(Ordering[Int].reverse)
      val inner = sorted.take(2).sum + node.subTreeOverKCount - 2
      val subInner = mapped.map(_._2).max
      (sorted.head + node.subTreeOverKCount - 2, if (inner > subInner) inner else subInner)
    }
  }
  class Node{
    private var mEdge: List[Node] = Nil
    def addEdge(to: Node): Unit = mEdge ::= to
    def edges: Iterable[Node] = mEdge
    var subTreeOverKCount: Int = 0
  }
  implicit class Scoped[V](val value: V){
    def let[A](func: V ⇒ A): A = func(value)
    def also(func: V ⇒ Unit): V = {
      func(value)
      value
    }
  }
}