//https://onlinejudge.u-aizu.ac.jp/problems/0575
object Main extends App {
  import scala.io.StdIn._
  solve
  def solve: Unit = {
    val Array(n, m, k, q) = readLine.trim.split(' ').map(_.toInt)
    val towns = Array.tabulate(n){_ ⇒ new Town}
    for (_ ← 0 until m){
      val Array(a, b, l) = readLine.trim.split(' ').map(_.toInt)
      towns(a - 1).addPathTo(b - 1, l)
      towns(b - 1).addPathTo(a - 1, l)
    }
    val minDistance = Array.tabulate(n){_ ⇒ Int.MaxValue}
    val queue = new PriorityQueue[(Int, Int)](n)(Ordering.by[(Int, Int), Int]{case (_, a) ⇒ a})
    val keySpecifier = Array.tabulate(n){i ⇒ queue.enqueue((i, Int.MaxValue))}
    for (_ ← 0 until k){
      val f = readLine.trim.toInt
      minDistance(f - 1) = 0
      queue.keyChange(keySpecifier(f - 1), (f - 1, 0))
    }
    while (queue.nonEmpty){
      val (town, distance) = queue.dequeue
      if (minDistance(town) == distance){
        for (Path(to, len) ← towns(town).path){
          if (minDistance(to) > distance + len) {
            minDistance(to) = distance + len
            queue.keyChange(keySpecifier(to), (to, distance + len))
          }
        }
      }
    }
    for (i ← towns.indices.sortBy(minDistance)(Ordering[Int].reverse)){
      for (Path(to, _) ← towns(i).path){
        if (minDistance(i) <= minDistance(to)) {
          towns(i).mergeTree(towns(to), minDistance(i))
        }
      }
    }
    for (_ ← 0 until q){
      val Array(s, t) = readLine.trim.split(' ').map(_.toInt)
      println(
        towns(s - 1).minDistance(towns(t - 1))
      )
    }
  }
  def lowerBound(min: Int, max: Int)(func: Int ⇒ Boolean): Int = {
    if (min >= max) min
    else {
      val mid = max - (max - min) / 2 - (max - min) % 2
      if (func(mid)){
        lowerBound(min, mid)(func)
      }else {
        lowerBound(mid + 1, max)(func)
      }
    }
  }
  case class ValueWithTime[T](value: T, time: Int)
  class LoggedUnionFindTree {
    private var mParent: Option[ValueWithTime[LoggedUnionFindTree]] = None
    private var mRoot: Option[LoggedUnionFindTree] = None
    private var mSize: Int = 1
    private def parentAt(time: Int): LoggedUnionFindTree = {
      mParent match{
        case Some(p) if p.time <= time ⇒ {
          var suspect = p.value
          while (suspect.mParent.isDefined && suspect.mParent.get.time <= time){
            suspect = suspect.mParent.get.value
          }
          suspect
        }
        case _ ⇒ this
      }
    }
    private def root: LoggedUnionFindTree = {
      mRoot = mRoot.map(_.root)
      mRoot match{
        case Some(r) ⇒ r
        case None ⇒ this
      }
    }
    private def path(res: List[LoggedUnionFindTree]): List[LoggedUnionFindTree] = {
      mParent.map(_.value.path(this::res)) match{
        case Some(p) ⇒ p
        case None ⇒ this::res
      }
    }
    private def path: List[LoggedUnionFindTree] = {
      path(Nil)
    }
    def isSameUnionAt(that: LoggedUnionFindTree, time: Int): Boolean = {
      parentAt(time) == that.parentAt(time)
    }
    def merge(that: LoggedUnionFindTree, time: Int): Unit = {
      val thisRoot = root
      val thatRoot = that.root
      if (thisRoot != thatRoot) {
        if (thisRoot.mSize > thatRoot.mSize) {
          thatRoot.mParent = Some(ValueWithTime(thisRoot, time))
          thatRoot.mRoot = Some(thisRoot)
          thisRoot.mSize += thatRoot.mSize
        } else {
          thisRoot.mParent = Some(ValueWithTime(thatRoot, time))
          thisRoot.mRoot = Some(thatRoot)
          thatRoot.mSize += thisRoot.mSize
        }
      }
    }
    def mergedTime(that: LoggedUnionFindTree): Int = {
      var thisPath = path
      var thatPath = that.path
      while (thisPath.nonEmpty && thatPath.nonEmpty && thisPath.head == thatPath.head){
        thisPath = thisPath.tail
        thatPath = thatPath.tail
      }
      if (thisPath.isEmpty) thatPath.head.mParent.get.time
      else if (thatPath.isEmpty) thisPath.head.mParent.get.time
      else if (thisPath.head.mParent.get.time < thatPath.head.mParent.get.time) thatPath.head.mParent.get.time
      else thisPath.head.mParent.get.time
    }
  }
  object PriorityQueue {
    class KeySpecifier private[PriorityQueue] (private[PriorityQueue] var index: Int) {
      def this(){this(-1)}
      private[PriorityQueue] var mIsValid: Boolean = true
    }
  }
  class PriorityQueue[K](private val maxSize: Int)(implicit val ordering: Ordering[K]) {
    private val mIndexHolder: Array[PriorityQueue.KeySpecifier] = Array.tabulate(maxSize){i ⇒ new PriorityQueue.KeySpecifier(i)}
    private var mSize: Int = 0
    private val mElements: Array[Option[K]] = Array.tabulate(maxSize){_ ⇒ None}
    def keyChange(keySpecifier: PriorityQueue.KeySpecifier, newKey:K): Unit = {
      if (!keySpecifier.mIsValid) throw new Exception
      if (ordering.compare(mElements(keySpecifier.index).get, newKey) > 0){
        mElements(keySpecifier.index) = Some(newKey)
        keyDecrease(keySpecifier.index)
      }else {
        mElements(keySpecifier.index) = Some(newKey)
        keyIncrease(keySpecifier.index)
      }
    }
    def enqueue(element: K): PriorityQueue.KeySpecifier = {
      mElements(mSize) = Some(element)
      mIndexHolder(mSize) = new PriorityQueue.KeySpecifier(mSize)
      val res = mIndexHolder(mSize)
      mSize += 1
      keyDecrease(mSize - 1)
      res
    }
    def dequeue: K = {
      val res = mElements(0).get
      mIndexHolder(0).mIsValid = false
      mElements(0) = None
      mSize -= 1
      swap(0, mSize)
      keyIncrease(0)
      res
    }
    def size:Int = mSize
    def isEmpty: Boolean = mSize == 0
    def nonEmpty: Boolean = mSize != 0
    private def swap(a: Int, b: Int): Unit = {
      val temp = mElements(a)
      mElements(a) = mElements(b)
      mElements(b) = temp
      val idx = mIndexHolder(a)
      mIndexHolder(a) = mIndexHolder(b)
      mIndexHolder(b) = idx
      mIndexHolder(a).index = a
      mIndexHolder(b).index = b
    }
    private def keyIncrease(index: Int): Unit = {
      if ((index + 1) * 2 < mSize){
        val min = if (ordering.compare(mElements((index + 1) * 2).get, mElements((index + 1) * 2 - 1).get) > 0) (index + 1) * 2 - 1 else (index + 1) * 2
        if (ordering.compare(mElements(index).get, mElements(min).get) > 0) {
          swap(min, index)
          keyIncrease(min)
        }
      }else if ((index + 1) * 2 - 1< mSize){
        if (ordering.compare(mElements(index).get, mElements((index + 1) * 2 - 1).get) > 0){
          swap(index, (index + 1) * 2 - 1)
          keyIncrease((index + 1) * 2 - 1)
        }
      }
    }
    private def keyDecrease(index: Int): Unit = {
      if (index != 0 && ordering.compare(mElements((index - 1) / 2).get, mElements(index).get) > 0){
        swap(index, (index - 1) / 2)
        keyDecrease((index - 1) / 2)
      }
    }
  }
  class Town{
    private var mPath: List[Path] = Nil
    private val mUnion: LoggedUnionFindTree = new LoggedUnionFindTree
    def addPathTo(to: Int, distance: Int): Unit = {
      mPath ::= Path(to, distance)
    }
    def mergeTree(that: Town, minDistance: Int): Unit = {
      mUnion.merge(that.mUnion, -minDistance)
    }
    def -(to: Town, minDistance: Int): Boolean = mUnion.isSameUnionAt(to.mUnion, -minDistance)
    def path = mPath
    def minDistance(that: Town): Int = {
      -mUnion.mergedTime(that.mUnion)
    }
  }
  case class Path(to: Int, distance: Int)
  implicit class ScopeFunc[T](private val value: T) {
    def let[A](func:T ⇒ A): A = func(value)
    def also(func:T ⇒ Unit): T = {
      func(value)
      value
    }
  }
}




Measured memory_bytes: 488752