You are given a tree with $N$ nodes (numbered $1$ through $N$). There are $K$ special nodes $f_{1},f_{2},\ldots,f_{K}$ in this tree.

We define $d(p,q)$ to be the number of edges on the unique path from node $p$ to node $q$.

You are given a node $a$. For each node $b$ from $1$ to $N$, find the maximum value of $d(a,u)-d(b,u)$ where $u$ is a special node, as well as any special node $u$ for which that maximum value is attained.

------ Input ------
The first line of the input contains a single integer $T$ denoting the number of test cases. The description of $T$ test cases follows.
The first line of each test case contains three space-separated integers $N$, $K$, $a$.
The second line contains $K$ space-separated integers $f_{1},f_{2},\ldots,f_{K}$.
$N-1$ lines follow. For each valid $i$, the $i$-th of these lines contains two space-separated integers $u_{i}$ and $v_{i}$ denoting an edge of the tree.

------ Output ------
For each test case, print two lines.

In the first line print $N$ space-separated integers. For each valid $i$, the $i$-th integer should be the maximum value of $d(a,u)-d(i,u)$ where $u$ is a special node.

In the second line print $N$ space-separated integers. For each valid $i$, the $i$-th integer should be any special node $u$ for which the maximum of $d(a,u)-d(i,u)$ is attained.

------ Constraints  ------
$1 ≤ T ≤ 200$
$1 ≤ K ≤ N ≤ 2 \cdot 10^{5}$
$1 ≤ a ≤ N$
$1 ≤ f_{i} ≤ N$ for each valid $i$
$f_{i} \neq f_{j}$ for each valid $i$ and $j$ such that $i \neq j$
$1 ≤ u_{i},v_{i} ≤ N$ for each valid $i$
the graph described on the input is a tree 
the sum of $N$ over all test cases does not exceed $4 \cdot 10^{5}$

------ Subtasks ------

Subtask #1 (10 points):
$T ≤ 11$
$N ≤ 200$
the sum of $N$ over all test cases does not exceed $400$

Subtask #2 (20 points):
$T ≤ 51$
$N ≤ 2000$
the sum of $N$ over all test cases does not exceed $4000$

Subtask #3 (30 points): 
It holds that $u_{i}=i$, $v_{i}=i+1$ for each valid $i$.

Subtask #4 (40 points): original constraints

------ Sample Input ------

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

------ Sample Output ------

1 2 0 1 1
2 2 2 2 2
-1 0 -1 1 1 2 0 2
5 5 5 6 5 6 5 8

------ Explanation ------
Example case 1:  The following picture shows the tree in the first example case with special nodes in bold:

The only special node is the node $2$ and $a=3$. Therefore, the desired maximum is $d(a,2)-d(b,2)=d(3,2)-d(b,2)=2-d(b,2)$ for each node $b$ and it is always attained for the special node $u=2$.

Example case 2: The following picture shows the tree in the second example case with special nodes bolded:

The special nodes are $6$, $5$ and $8$, and $a=2$. The maximum values of $d(a,u)-d(b,u)$ ($u$ being a special node) for each $b$ are as follows:

$b=1$: The maximum value of $d(2,u)-d(1,u)$ is $-1$ and it is achieved for $u=5$ since $d(2,5)-d(1,5)=1-2=-1$.

$b=2$: The maximum value of $d(2,u)-d(2,u)$ is $0$ and it is achieved for $u=5$ since $d(2,5)-d(2,5)=1-1=0$.

$b=3$: The maximum value of $d(2,u)-d(3,u)$ is $-1$ and it is achieved for $u=5$ since $d(2,5)-d(3,5)=1-2=-1$.

$b=4$: The maximum value of $d(2,u)-d(4,u)$ is $1$ and it is achieved for $u=6$ since $d(2,6)-d(4,6)=2-1=1$.

$b=5$: The maximum value of $d(2,u)-d(5,u)$ is $1$ and it is achieved for $u=5$ since $d(2,5)-d(5,5)=1-0=1$.

$b=6$: The maximum value of $d(2,u)-d(6,u)$ is $2$ and it is achieved for $u=6$ since $d(2,6)-d(6,6)=2-0=2$.

$b=7$: The maximum value of $d(2,u)-d(7,u)$ is $0$ and it is achieved for $u=5$ since $d(2,5)-d(7,5)=1-1=0$.

$b=8$: The maximum value of $d(2,u)-d(8,u)$ is $2$ and it is achieved for $u=8$ since $d(2,8)-d(8,8)=2-0=2$.

Source: codechef | Difficulty: VERY_HARD
Tags: Graph algorithms

Graph traversal


Solutions:
import sys
import copy
import math
isIo = False
sys.setrecursionlimit(10 ** 6)
if isIo:
	sys.stdin = open('input.txt', 'r')
	sys.stdout = open('output.txt', 'w')
isTakeTestCase = True

def scanIntList():
	return map(int, input().split())

def printList(lst):
	for elem in lst:
		print(elem, end=' ')
	print()

def markDistance(tree, isSpecial, dist, parentOfSpec, root, par, distanceFromRoot):
	dist[root] = distanceFromRoot + 1
	dep = int(10000000000.0)
	depSpec = -1
	if root in isSpecial:
		parentOfSpec[root] = root
		dep = 0
		depSpec = root
	for node in tree[root]:
		if par != node:
			(specNode, tempDep) = markDistance(tree, isSpecial, dist, parentOfSpec, node, root, distanceFromRoot + 1)
			if dep > tempDep:
				dep = tempDep
				depSpec = specNode
	parentOfSpec[root] = depSpec
	return (parentOfSpec[root], dep + 1)

def dfs(tree, dist, parentOfSpec, objective, myspec, root, par, specAnc):
	if parentOfSpec[root] != -1:
		objective[root] = dist[root]
		specAnc = root
		myspec[root] = parentOfSpec[root]
	else:
		objective[root] = 2 * dist[specAnc] - dist[root]
		myspec[root] = parentOfSpec[specAnc]
	for node in tree[root]:
		if par != node:
			dfs(tree, dist, parentOfSpec, objective, myspec, node, root, specAnc)

def solve():
	(n, k, a) = scanIntList()
	special = list(scanIntList())
	isSpecial = {}
	for node in special:
		isSpecial[node] = True
	tree = [[] for _ in range(n + 1)]
	dist = [-1 for _ in range(n + 1)]
	objective = [-1 for _ in range(n + 1)]
	parentOfSpec = [0 for _ in range(n + 1)]
	myspec = [-1 for _ in range(n + 1)]
	for _ in range(n - 1):
		(x, y) = scanIntList()
		tree[x].append(y)
		tree[y].append(x)
	markDistance(tree, isSpecial, dist, parentOfSpec, a, -1, -1)
	dfs(tree, dist, parentOfSpec, objective, myspec, a, -1, -1)
	for i in range(1, n + 1):
		print(objective[i], end=' ')
	print()
	for i in range(1, n + 1):
		print(myspec[i], end=' ')
	print()

def driver():
	testCases = 1
	if isTakeTestCase:
		testCases = int(input())
	for i in range(testCases):
		solve()
driver()


from sys import setrecursionlimit
setrecursionlimit(10 ** 8)

def dfs(root, depth, parent=-1):
	sp = -1
	parent_list[root] = parent
	for e in adj_list[root]:
		if e != parent_list[root]:
			temp = dfs(e, depth + 1, root)
			if temp != -1 and sp == -1:
				sp = temp
	if sp_nodes[root]:
		sp = root
	if sp != -1:
		ans_list[root] = depth
		ans_node_list[root] = sp
	return sp

def dfs2(root, depth, L, parent):
	ans_list[root] = ans_list[L] - depth
	ans_node_list[root] = ans_node_list[L]
	for e in adj_list[root]:
		if e != parent:
			dfs2(e, depth + 1, L, root)
t = int(input())
for _ in range(t):
	(n, k, a) = map(int, input().split())
	a -= 1
	f = map(int, input().split())
	sp_nodes = [False] * n
	for i in f:
		sp_nodes[i - 1] = True
	adj_list = [[] for i in range(n)]
	parent_list = [-1] * n
	ans_list = [-1] * n
	ans_node_list = [-1] * n
	for _ in range(n - 1):
		(u, v) = map(int, input().split())
		u -= 1
		v -= 1
		adj_list[u].append(v)
		adj_list[v].append(u)
	dfs(a, 0)
	for i in range(n):
		if ans_list[i] == -1 and parent_list[i] != -1 and (ans_node_list[parent_list[i]] != -1):
			dfs2(i, 1, parent_list[i], parent_list[i])
	print(*ans_list)
	print(' '.join(map(str, [x + 1 for x in ans_node_list])))
	print()


import sys
sys.setrecursionlimit(10 ** 7)

class Graph:

	def __init__(self, N):
		self.N = N
		self.adj = [[] for i in range(N + 1)]
		self.hasSpInSub = [False] * (N + 1)
		self.nearestAncestor = [0] * (N + 1)
		self.level = [0] * (N + 1)
		self.anySpNode = [0] * (N + 1)

	def addEdge(self, a, b):
		self.adj[a].append(b)
		self.adj[b].append(a)

	def prep(self, a, dic):

		def dfs(node, par, depth):
			self.level[node] = depth
			for cnode in self.adj[node]:
				if cnode == par:
					continue
				v = dfs(cnode, node, depth + 1)
				if v:
					self.anySpNode[node] = v
				self.hasSpInSub[node] = v or self.hasSpInSub[node]
			if node in dic:
				self.hasSpInSub[node] = True
				self.anySpNode[node] = node
			return self.anySpNode[node]
		dfs(a, 0, 0)

		def dfs1(node, par, latestSpecialAncestor):
			if self.hasSpInSub[node]:
				latestSpecialAncestor = node
			self.nearestAncestor[node] = latestSpecialAncestor
			for cnode in self.adj[node]:
				if cnode == par:
					continue
				dfs1(cnode, node, latestSpecialAncestor)
		dfs1(a, 0, a)

	def show(self):
		for node in range(1, self.N + 1):
			print('node', node, 'Has Special Node', self.hasSpInSub[node])
		print()
		for node in range(1, self.N + 1):
			print('Node', node, 'Nearest Special Ancestor', self.nearestAncestor[node])
		print('-' * 40)

	def dist(self, u, v):
		return self.level[v] - self.level[u]

def solve(N, f, a):
	spNodes = {}
	for node in f:
		spNodes[node] = 1
	gr = Graph(N)
	for i in range(N - 1):
		(u, v) = map(int, input().split())
		gr.addEdge(u, v)
	gr.prep(a, spNodes)
	Distances = []
	SpecialNode = []
	for b in range(1, N + 1):
		nearestAncestor = gr.nearestAncestor[b]
		v = gr.dist(a, nearestAncestor) - gr.dist(nearestAncestor, b)
		Distances.append(v)
		SpecialNode.append(gr.anySpNode[nearestAncestor])
	print(*Distances)
	print(*SpecialNode)
for case in range(int(input())):
	(N, K, a) = map(int, input().split())
	f = list(map(int, input().split()))
	solve(N, f, a)


import math
import sys

def solve():
	(n, k, a) = map(int, input().split())
	a -= 1
	temp = list(map(int, input().split()))
	spc = [False] * n
	for i in temp:
		spc[i - 1] = True
	edges = []
	for i in range(n):
		edges.append([])
	for i in range(n - 1):
		(u, v) = map(int, input().split())
		edges[u - 1].append(v - 1)
		edges[v - 1].append(u - 1)
	vis = [False] * n
	parent = [None] * n
	depth = [0] * n
	dist = [None] * n
	a_to_spc = [None] * n
	nodes = [a]
	max_depth = 0
	levels = []
	for i in range(n):
		levels.append([])
	while nodes:
		node = nodes.pop()
		levels[depth[node]].append(node)
		vis[node] = True
		for child in edges[node]:
			if not vis[child]:
				nodes.append(child)
				depth[child] = depth[node] + 1
				parent[child] = node
		if depth[node] > max_depth:
			max_depth = depth[node]
	vis = [False] * n
	for i in range(max_depth, -1, -1):
		while levels[i]:
			node = levels[i].pop()
			if spc[node]:
				dist[node] = depth[node]
				a_to_spc[node] = node
			parent_node = parent[node]
			if dist[node] is not None:
				u = a_to_spc[node]
				children = [x for x in edges[node] if dist[x] is None and x != parent_node]
				while children:
					child = children.pop()
					dist[child] = 2 * depth[node] - depth[child]
					a_to_spc[child] = u
					children.extend([x for x in edges[child] if dist[x] is None])
			if parent_node != None and dist[node] != None:
				a_to_spc[parent_node] = a_to_spc[node]
				dist[parent_node] = depth[parent_node]
	for i in range(n):
		print(dist[i], end=' ')
	print('')
	for i in range(n):
		print(a_to_spc[i] + 1, end=' ')
	print('')
t = int(input())
for i in range(t):
	solve()


T = int(input())
for _ in range(T):
	(n, k, a) = [int(x) for x in input().split()]
	special = [int(x) for x in input().split()]
	graph = {i + 1: [] for i in range(n)}
	for i in range(n - 1):
		(u, v) = [int(x) for x in input().split()]
		graph[u].append(v)
		graph[v].append(u)
	adist = {i + 1: 10 ** 6 for i in range(n)}
	parent = {i + 1: 0 for i in range(n)}
	queue = [a]
	visited = {a}
	adist[a] = 0
	while queue:
		u = queue.pop(0)
		for v in graph[u]:
			if v not in visited:
				queue.append(v)
				visited.add(v)
				adist[v] = min(adist[v], adist[u] + 1)
				parent[v] = u
	good = {a: special[0]}
	for u in special:
		v = u
		while v not in good:
			good[v] = u
			v = parent[v]
	gdist = {i + 1: 10 ** 6 for i in range(n)}
	snode = {i + 1: special[0] for i in range(n)}
	queue = [a]
	visited = {a}
	gdist[a] = 0
	while queue:
		u = queue.pop(0)
		for v in graph[u]:
			if v not in visited:
				queue.append(v)
				visited.add(v)
				if v in good:
					gdist[v] = 0
					snode[v] = good[v]
				else:
					gdist[v] = min(gdist[v], gdist[u] + 1)
					snode[v] = snode[parent[v]]
	fdist = [adist[i + 1] - 2 * gdist[i + 1] for i in range(n)]
	fnode = [snode[i + 1] for i in range(n)]
	print(*fdist)
	print(*fnode)


from collections import defaultdict, deque

def bfs(start, version):
	seen = set()
	q = deque()
	q.append(start)
	adist[start] = 0
	while q:
		v = q.popleft()
		if v not in seen:
			seen.add(v)
			for neighbor in d[v]:
				if neighbor not in seen:
					q.append(neighbor)
					if version == 1:
						adist[neighbor] = min(adist[neighbor], adist[v] + 1)
						parent[neighbor] = v
					elif neighbor in good:
						gdist[neighbor] = 0
						snode[neighbor] = good[neighbor]
					else:
						gdist[neighbor] = min(gdist[neighbor], gdist[v] + 1)
						snode[neighbor] = snode[parent[neighbor]]
t = int(input())
for _ in range(t):
	(n, k, a) = map(int, input().split())
	f = [int(i) for i in input().split()]
	d = defaultdict(list)
	for _ in range(n - 1):
		(u, v) = map(int, input().split())
		d[u].append(v)
		d[v].append(u)
	adist = {i + 1: 10 ** 6 for i in range(n)}
	parent = {i + 1: -1 for i in range(n)}
	bfs(a, 1)
	good = {a: f[0]}
	for u in f:
		v = u
		while v not in good:
			good[v] = u
			v = parent[v]
	gdist = {i + 1: 10 ** 6 for i in range(n)}
	snode = {i + 1: f[0] for i in range(n)}
	gdist[a] = 0
	bfs(a, 2)
	fdist = [adist[i + 1] - 2 * gdist[i + 1] for i in range(n)]
	fnode = [snode[i + 1] for i in range(n)]
	print(*fdist)
	print(*fnode)


from sys import stdin, stdout
from collections import defaultdict as dd
from collections import deque
import math
import sys
import random
sys.setrecursionlimit(int(10000000.0))
input = stdin.readline
flush = stdout.flush
p = int(1000000000.0) + 7

def dfs(root, x):
	vis[root] = True
	dis[root] = x
	for i in d[root]:
		if vis[i] == False:
			dfs(i, x + 1)

def dfs2(root):
	has_after = -1
	vis[root] = True
	for i in d[root]:
		if vis[i] == False:
			has_after = max(dfs2(i), has_after)
			if i in f:
				has_after = i
	if root in f:
		has_after = root
	if has_after != -1:
		pos[root] = has_after
	return has_after

def dfs3(root, b, repp):
	has_above = b
	has_rep = repp
	if pos[root] != -1:
		has_above = root
		has_rep = pos[root]
	abv[root] = has_above
	rep[root] = has_rep
	vis[root] = True
	for i in d[root]:
		if vis[i] == False:
			dfs3(i, has_above, has_rep)
tc = 1
tc = int(input())
for _ in range(tc):
	(n, k, a) = map(int, input().split())
	a -= 1
	f = list(map(int, input().split()))
	for i in range(k):
		f[i] -= 1
	f = set(f)
	d = dd(lambda : [])
	for i in range(n - 1):
		(u, v) = map(int, input().split())
		u -= 1
		v -= 1
		d[u].append(v)
		d[v].append(u)
	vis = [False for i in range(n)]
	dis = [-1 for i in range(n)]
	dfs(a, 0)
	vis = [False for i in range(n)]
	pos = [-1 for i in range(n)]
	pos[a] = dfs2(a)
	vis = [False for i in range(n)]
	abv = [-1 for i in range(n)]
	rep = [-1 for i in range(n)]
	dfs3(a, -1, -1)
	a1 = []
	a2 = []
	for i in range(n):
		if pos[i] != -1:
			a1.append(dis[i])
			a2.append(pos[i] + 1)
		elif abv[i] != -1:
			ds1 = dis[abv[i]]
			ds2 = dis[i] - dis[abv[i]]
			a1.append(ds1 - ds2)
			a2.append(rep[i] + 1)
	print(*a1)
	print(*a2)


import collections
import math
t = int(input())
for i in range(t):
	(n, k, a) = [int(x) for x in input().split()]
	lis_k = set([int(x) for x in input().split()])
	graph = collections.defaultdict(list)
	graph_2 = collections.defaultdict(list)
	for i1 in range(n - 1):
		(node1, node2) = [int(x) for x in input().split()]
		graph[node1].append(node2)
		graph[node2].append(node1)
		graph_2[node1].append(node2)
		graph_2[node2].append(node1)
	if n == 1:
		print(0)
		print(1)
		continue
	lis_temp = [[a, -1, False, -1]]
	lis_k_new = dict()
	while lis_temp:
		(node, parent, below, special) = lis_temp[-1]
		if node not in graph_2 or not graph_2[node]:
			lis_temp.pop()
			if node == a:
				if below:
					lis_k_new[a] = special
				continue
			if below:
				lis_k_new[node] = special
				lis_temp[-1][2] = True
				lis_temp[-1][3] = special
			if node in lis_k:
				lis_temp[-1][2] = True
				lis_temp[-1][3] = node
			continue
		node_child = graph_2[node].pop()
		if node_child == parent:
			if not graph_2[node]:
				lis_temp.pop()
				if node == a:
					if below:
						lis_k_new[a] = special
					continue
				if below:
					lis_k_new[node] = special
					lis_temp[-1][2] = True
					lis_temp[-1][3] = special
				if node in lis_k:
					lis_temp[-1][2] = True
					lis_temp[-1][3] = node
				continue
			node_child = graph_2[node].pop()
		lis_temp.append([node_child, node, False, -1])
	parent_dict = dict()
	avail_dict = dict()
	special_node_dict = dict()
	special_node_prev = dict()
	last_k_prev = dict()
	min_value = [math.inf for x in range(n)]
	lis = [[a, -1, 0, 0, -1]]
	while lis:
		(node, parent, depth, last_k, special_node) = lis.pop()
		if node not in parent_dict:
			parent_dict[node] = parent
			avail_dict[node] = False
			if node in lis_k_new:
				last_k = depth
				avail_dict[node] = True
				special_node = lis_k_new[node]
			if node in lis_k:
				last_k = depth
				avail_dict[node] = True
				special_node = node
			min_value[node - 1] = last_k - (depth - last_k)
			special_node_dict[node] = special_node
			special_node_prev[node] = special_node
			last_k_prev[node] = last_k
		if not graph[node]:
			if avail_dict[node]:
				min_value[node - 1] = depth
			if node != a:
				parent_node = parent_dict[node]
				lis.append([parent_node, parent_dict[parent_node], depth - 1, last_k_prev[parent_node], special_node_prev[parent_node]])
				if avail_dict[node]:
					avail_dict[parent_node] = True
					special_node_dict[parent_node] = special_node_dict[node]
			continue
		node_child = graph[node].pop()
		if node_child != parent:
			lis.append([node_child, node, depth + 1, last_k, special_node])
		else:
			if not graph[node]:
				if avail_dict[node]:
					min_value[node - 1] = depth
				if node != a:
					parent_node = parent_dict[node]
					lis.append([parent_node, parent_dict[parent_node], depth - 1, last_k_prev[parent_node], special_node_prev[parent_node]])
					if avail_dict[node]:
						avail_dict[parent_node] = True
						special_node_dict[parent_node] = special_node_dict[node]
				continue
			node_child = graph[node].pop()
			lis.append([node_child, node, depth + 1, last_k, special_node])
	print(*min_value)
	list_k = list(lis_k)
	for i1 in special_node_dict:
		if special_node_dict[i1] == -1:
			special_node_dict[i1] = list_k[0]
	print(*[special_node_dict[x] for x in range(1, n + 1)])