Treelabeling (Codeforces 1605D)
Tags: Greedy, games

Eikooc and Sushi play a game.The game is played on a tree having $$$n$$$ nodes numbered $$$1$$$ to $$$n$$$. Recall that a tree having $$$n$$$ nodes is an undirected, connected graph with $$$n-1$$$ edges.They take turns alternately moving a token on the tree. Eikooc makes the first move, placing the token on any node of her choice. Sushi makes the next move, followed by Eikooc, followed by Sushi, and so on. In each turn after the first, a player must move the token to a node $$$u$$$ such that   $$$u$$$ is adjacent to the node $$$v$$$ the token is currently on  $$$u$$$ has not been visited before  $$$u \oplus v \leq min(u, v)$$$ Here $$$x \oplus y$$$ denotes the bitwise XOR operation on integers $$$x$$$ and $$$y$$$.Both the players play optimally. The player who is unable to make a move loses.The following are examples which demonstrate the rules of the game.     Suppose Eikooc starts the game by placing the token at node $$$4$$$. Sushi then moves the token to node $$$6$$$, which is unvisited and adjacent to $$$4$$$. It also holds that $$$6 \oplus 4 = 2 \leq min(6, 4)$$$. In the next turn, Eikooc moves the token to node $$$5$$$, which is unvisited and adjacent to $$$6$$$. It holds that $$$5 \oplus 6 = 3 \leq min(5, 6)$$$. Sushi has no more moves to play, so she loses.   Suppose Eikooc starts the game by placing the token at node $$$3$$$. Sushi moves the token to node $$$2$$$, which is unvisited and adjacent to $$$3$$$. It also holds that $$$3 \oplus 2 = 1 \leq min(3, 2)$$$. Eikooc cannot move the token to node $$$6$$$ since $$$6 \oplus 2 = 4 \nleq min(6, 2)$$$. Since Eikooc has no moves to play, she loses. Before the game begins, Eikooc decides to sneakily relabel the nodes of the tree in her favour. Formally, a relabeling is a permutation $$$p$$$ of length $$$n$$$ (sequence of $$$n$$$ integers wherein each integer from $$$1$$$ to $$$n$$$ occurs exactly once) where $$$p_i$$$ denotes the new numbering of node $$$i$$$.She wants to maximize the number of nodes she can choose in the first turn which will guarantee her a win. Help Eikooc find any relabeling which will help her do so. 

Input: The first line contains a single integer $$$t~(1 \le t \le 10^5)$$$  — the number of test cases. The description of each test case is as follows.The first line of each test case contains an integer $$$n~(1 \le n \le 2 \cdot 10^5)$$$  — the number of nodes in the tree.The next $$$n-1$$$ lines contain two integers $$$u$$$ and $$$v$$$ $$$(1 \le u, v \le n; u \neq v)$$$  — denoting an edge between nodes $$$u$$$ and $$$v$$$.It is guaranteed that the sum of $$$n$$$ over all test cases does not exceed $$$2 \cdot 10^5$$$.

Output: For each test case print any suitable relabeling  — a permutation of length $$$n$$$ which maximizes the number of nodes that can be chosen in the first turn that guarantee a win for Eikooc. If there are multiple such relabelings, you may print any of them.

Note: In the first test case, Eikooc has only one choice. Sushi will have no moves to play after Eikooc chooses this node and Eikooc will win.In the second test case, $$$1 \oplus 2 = 3 \nleq min(1, 2)$$$. Hence, after Eikooc picks either of the nodes, Sushi will have no moves to play and Eikooc will win. Both $$$\{1, 2\}$$$ and $$$\{2, 1\}$$$ are optimal relabelings.

Sample Inputs:
3
1
2
1 2
3
1 2
1 3

Sample Outputs:
1
2 1
1 2 3

Solution (Python):
import sys
from collections import deque

def solve(n, edges):
    vis = [-1] * (n + 1)
    g = [set() for _ in range(n + 1)]
    for (u, v) in edges:
        g[u].add(v)
        g[v].add(u)
    subs = [[], []]
    for i in range(1, n + 1):
        if vis[i] < 0:
            q = deque([i])
            vis[i] = 0
            subs[0].append(i)
            while q:
                u = q.popleft()
                for v in g[u]:
                    if vis[v] < 0:
                        g[v].remove(u)
                        vis[v] = 1 - vis[u]
                        q.append(v)
                        subs[vis[v]].append(v)
    subs.sort(key=lambda it: len(it))
    m = len(subs[0])
    val = []
    while m:
        b = m & -m
        val.extend(list(range(b, b << 1)))
        m -= b
    st = set(val)
    for i in subs[0]:
        vis[i] = val.pop()
    k = 1
    for i in subs[1]:
        while k in st:
            k += 1
        vis[i] = k
        k += 1
    return ' '.join(map(str, vis[1:]))
t = int(sys.stdin.readline())
ans = []
for _ in range(t):
    n = int(sys.stdin.readline())
    edges = [tuple(map(int, sys.stdin.readline().split())) for _ in range(n - 1)]
    ans.append(solve(n, edges))
print('\n'.join(ans))

Solution (Python):
import sys
INF = 10 ** 20
MOD = 10 ** 9 + 7
from math import gcd
from math import ceil, log2, factorial
from collections import defaultdict as dd, Counter
from bisect import bisect_left as bl, bisect_right as br
sys.setrecursionlimit(MOD)

def fastio():
    import sys
    from io import StringIO
    from atexit import register
    global input
    sys.stdin = StringIO(sys.stdin.read())
    input = lambda : sys.stdin.readline().rstrip('\r\n')
    sys.stdout = StringIO()
    register(lambda : sys.__stdout__.write(sys.stdout.getvalue()))
fastio()
I = lambda : list(map(int, input().split()))
TESTS = 1
''

def solve():
    (n,) = I()
    graf = [[] for i in range(n)]
    for i in range(n - 1):
        (x, y) = I()
        x -= 1
        y -= 1
        graf[x].append(y)
        graf[y].append(x)
    nodes = [[], []]

    def dfs(x, p, depth):
        q = [x]
        depth = [-1] * n
        depth[0] = 0
        while q:
            el = q.pop()
            nodes[depth[el] % 2].append(el)
            for i in graf[el]:
                if depth[i] >= 0:
                    continue
                depth[i] = depth[el] + 1
                q.append(i)
    dfs(0, -1, 0)
    kaka = dd(list)
    for i in range(n):
        kaka[(i + 1).bit_length()].append(i + 1)
    t = []
    for i in kaka:
        t.append((len(kaka[i]), kaka[i]))
    t.sort()
    ans = [0] * n
    while t:
        (l, a) = t.pop()
        (l0, l1) = (len(nodes[0]), len(nodes[1]))
        if l0 > l1:
            for i in a:
                if nodes[0]:
                    ans[nodes[0].pop()] = i
        else:
            for i in a:
                if nodes[1]:
                    ans[nodes[1].pop()] = i
    print(*ans)

def main():
    if not TESTS:
        solve()
        return
    (t,) = I()
    while t:
        solve()
        t -= 1
if __name__ == '__main__':
    main()

Solution (Python):
import io, os, sys
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

def tree_labelling(n, connections):
    colors = [False] * n
    color = 1
    current_nodes = [1]
    next_nodes = []
    while len(current_nodes) > 0:
        for current_node in current_nodes:
            colors[current_node - 1] = color
            for connected_node in connections[current_node]:
                if colors[connected_node - 1] is False:
                    next_nodes += [connected_node]
        current_nodes = next_nodes
        next_nodes = []
        color *= -1
    count_plus = 0
    for color in colors:
        if color == 1:
            count_plus += 1
    count_minus = n - count_plus
    labels_a = []
    labels_b = []
    smaller_group = min(count_minus, count_plus)
    labels_by_highest_bit = {}
    highest = 0
    capacity = 1
    count = 0
    for number in range(1, n + 1):
        if highest in labels_by_highest_bit:
            labels_by_highest_bit[highest] += [number]
        else:
            labels_by_highest_bit[highest] = [number]
        count += 1
        if count == capacity:
            capacity *= 2
            count = 0
            highest += 1
    highest = 0
    for _ in range(len(labels_by_highest_bit)):
        last = smaller_group % 2
        if last == 1:
            labels_a += labels_by_highest_bit[highest]
        else:
            labels_b += labels_by_highest_bit[highest]
        smaller_group //= 2
        highest += 1
    if count_plus <= count_minus:
        labels_by_color = {1: labels_a, -1: labels_b}
    else:
        labels_by_color = {1: labels_b, -1: labels_a}
    for i in range(n):
        colors[i] = labels_by_color[colors[i]].pop()
    sys.stdout.write(f"{' '.join(map(str, colors))}\n")
for _ in range(int(input())):
    connections = {1: []}
    n = int(input())
    for _ in range(n - 1):
        (a, b) = map(int, input().decode().split(' '))
        for (i, j) in [(a, b), (b, a)]:
            if i in connections:
                connections[i] += [j]
            else:
                connections[i] = [j]
    tree_labelling(n, connections)