Colored Subgraphs (Codeforces 1796E)
Tags: Greedy, games

Monocarp has a tree, consisting of $$$n$$$ vertices.He is going to select some vertex $$$r$$$ and perform the following operations on each vertex $$$v$$$ from $$$1$$$ to $$$n$$$:   set $$$d_v$$$ equal to the distance from $$$v$$$ to $$$r$$$ (the number of edges on the shortest path);  color $$$v$$$ some color. A nice coloring satisfies two conditions:   for each pair of vertices of the same color $$$(v, u)$$$, there exists a path from $$$v$$$ to $$$u$$$ that only visits vertices of the same color;  for each pair of vertices of the same color $$$(v, u)$$$, $$$d_v \neq d_u$$$. Note that Monocarp can choose any amount of different colors he wants to use.For each used color, he then counts the number of vertices of this color. The cost of the tree is the minimum of these numbers.What can be the maximum cost of the tree?

Input: The first line contains a single integer $$$t$$$ ($$$1 \le t \le 10^4$$$) — the number of testcases.The first line of each testcase contains a single integer $$$n$$$ ($$$3 \le n \le 2 \cdot 10^5$$$) — the number of vertices in the tree.Each of the next $$$n-1$$$ lines contains two integers $$$v$$$ and $$$u$$$ ($$$1 \le v, u \le n$$$) — the description of an edge.The given edges form a tree. The sum of $$$n$$$ over all testcases doesn't exceed $$$2 \cdot 10^5$$$.

Output: For each testcase print a single integer — the maximum possible cost of the tree.


Sample Inputs:
4
4
1 2
2 3
3 4
5
1 2
1 3
1 4
1 5
3
1 3
3 2
7
3 2
2 5
7 5
3 1
1 6
1 4

Sample Outputs:
4
1
3
3

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

def f(u, v):
    return u * (n + 1) + v

def make_graph(n, m):
    (x, s) = ([0] * (2 * m), [0] * (n + 3))
    for i in range(0, 2 * m, 2):
        (u, v) = map(int, input().split())
        s[u + 2] += 1
        s[v + 2] += 1
        (x[i], x[i + 1]) = (u, v)
    for i in range(3, n + 3):
        s[i] += s[i - 1]
    G = [0] * (2 * m)
    for i in range(2 * m):
        j = x[i] + 1
        G[s[j]] = x[i ^ 1]
        s[j] += 1
    return (G, s)

def bfs(s):
    q = [0] * n
    q[0] = s
    visit = [0] * (n + 1)
    visit[s] = 1
    e = [0] * (2 * (n - 1))
    s1 = [0] * (n + 3)
    l = 1
    for k in range(n):
        i = q[k]
        for v in range(s0[i], s0[i + 1]):
            j = G[v]
            if not visit[j]:
                q[l] = j
                visit[j] = 1
                (e[2 * l - 2], e[2 * l - 1]) = (i, j)
                l += 1
                s1[i + 2] += 1
    return (q, e, s1)
t = int(input())
ans = []
inf = pow(10, 9) + 1
for _ in range(t):
    n = int(input())
    (G, s0) = make_graph(n, n - 1)
    (p, e, s1) = bfs(1)
    for i in range(3, n + 3):
        s1[i] += s1[i - 1]
    child = [0] * (n - 1)
    for i in range(0, 2 * (n - 1), 2):
        j = e[i] + 1
        child[s1[j]] = e[i ^ 1]
        s1[j] += 1
    dp1 = [1] * (n + 1)
    mi1 = [inf] * (n + 1)
    for i in p[::-1]:
        x = [dp1[child[j]] for j in range(s1[i], s1[i + 1])]
        for j in range(s1[i], s1[i + 1]):
            mi1[i] = min(mi1[i], mi1[child[j]])
        if len(x) == 1:
            dp1[i] = x[0] + 1
        elif len(x) > 1:
            x.sort()
            dp1[i] = x[0] + 1
            mi1[i] = min(mi1[i], x[1])
    dp2 = [1] * (n + 1)
    dp2[1] = 0
    mi2 = [inf] * (n + 1)
    for i in p:
        c = [child[j] for j in range(s1[i], s1[i + 1])]
        if not c:
            continue
        x = [f(dp1[j], j) for j in c]
        if i ^ 1:
            x.append(f(dp2[i], i))
        x.sort()
        x = x[:3]
        if len(x) == 1:
            j = c[0]
            (dp2[j], mi2[j]) = (dp2[i] + 1, min(mi2[i], mi2[j]))
        elif len(x) == 2:
            for j in c:
                for y in x:
                    (x1, x2) = divmod(y, n + 1)
                    if x2 ^ j:
                        dp2[j] = x1 + 1
                        break
        else:
            for j in c:
                f0 = 0
                for y in x:
                    (x1, x2) = divmod(y, n + 1)
                    if x2 ^ j and (not f0):
                        (dp2[j], f0) = (x1 + 1, 1)
                    elif x2 ^ j:
                        mi2[j] = min(mi2[j], x1)
                        break
        l = [inf] + [mi1[j] for j in c]
        r = [mi1[j] for j in c] + [inf]
        for j in range(1, len(c) + 1):
            l[j] = min(l[j], l[j - 1])
        for j in range(len(c) - 1, -1, -1):
            r[j] = min(r[j], r[j + 1])
        for j in range(len(c)):
            mi2[c[j]] = min(mi2[c[j]], l[j], r[j + 1], mi2[i])
    ans0 = -inf
    for i in range(1, n + 1):
        c = [child[j] for j in range(s1[i], s1[i + 1])]
        x = [dp1[j] for j in c] + [inf]
        if i ^ 1:
            x += [dp2[i]]
        x.sort()
        ans1 = x[0] + 1
        y = [mi1[j] for j in c]
        if i ^ 1:
            y += [mi2[i]]
        ans1 = min(x[0] + 1, x[1], min(y))
        ans0 = max(ans0, ans1)
    ans.append(ans0)
sys.stdout.write('\n'.join(map(str, ans)))

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

def make_graph(n, m):
    (x, s) = ([0] * (2 * m), [0] * (n + 3))
    for i in range(0, 2 * m, 2):
        (u, v) = map(int, input().split())
        s[u + 2] += 1
        s[v + 2] += 1
        (x[i], x[i + 1]) = (u, v)
    for i in range(3, n + 3):
        s[i] += s[i - 1]
    G = [0] * (2 * m)
    for i in range(2 * m):
        j = x[i] + 1
        G[s[j]] = x[i ^ 1]
        s[j] += 1
    return (G, s)

def bfs(s):
    q = [0] * n
    q[0] = s
    visit = [0] * (n + 1)
    visit[s] = 1
    e = [0] * (2 * (n - 1))
    s1 = [0] * (n + 3)
    l = 1
    for k in range(n):
        i = q[k]
        for v in range(s0[i], s0[i + 1]):
            j = G[v]
            if not visit[j]:
                q[l] = j
                visit[j] = 1
                (e[2 * l - 2], e[2 * l - 1]) = (i, j)
                l += 1
                s1[i + 2] += 1
    return (q, e, s1)
t = int(input())
ans = []
inf = pow(10, 9) + 1
for _ in range(t):
    n = int(input())
    (G, s0) = make_graph(n, n - 1)
    (p, e, s1) = bfs(1)
    for i in range(3, n + 3):
        s1[i] += s1[i - 1]
    child = [0] * (n - 1)
    for i in range(0, 2 * (n - 1), 2):
        j = e[i] + 1
        child[s1[j]] = e[i ^ 1]
        s1[j] += 1
    dp1 = [1] * (n + 1)
    mi1 = [inf] * (n + 1)
    for i in p[::-1]:
        x = [dp1[child[j]] for j in range(s1[i], s1[i + 1])]
        for j in range(s1[i], s1[i + 1]):
            mi1[i] = min(mi1[i], mi1[child[j]])
        if len(x) == 1:
            dp1[i] = x[0] + 1
        elif len(x) > 1:
            x.sort()
            dp1[i] = x[0] + 1
            mi1[i] = min(mi1[i], x[1])
    dp2 = [1] * (n + 1)
    dp2[1] = 0
    mi2 = [inf] * (n + 1)
    for i in p:
        c = [child[j] for j in range(s1[i], s1[i + 1])]
        if not c:
            continue
        x = [[dp1[j], j] for j in c]
        if i ^ 1:
            x.append([dp2[i], i])
        x.sort()
        if len(x) == 1:
            j = c[0]
            (dp2[j], mi2[j]) = (dp2[i] + 1, min(mi2[i], mi2[j]))
        elif len(x) == 2:
            for j in c:
                for (x1, x2) in x:
                    if x2 ^ j:
                        dp2[j] = x1 + 1
                        break
        else:
            for j in c:
                f = 0
                for (x1, x2) in x:
                    if x2 ^ j and (not f):
                        (dp2[j], f) = (x1 + 1, 1)
                    elif x2 ^ j:
                        mi2[j] = min(mi2[j], x1)
                        break
        l = [inf] + [mi1[j] for j in c]
        r = [mi1[j] for j in c] + [inf]
        for j in range(1, len(c) + 1):
            l[j] = min(l[j], l[j - 1])
        for j in range(len(c) - 1, -1, -1):
            r[j] = min(r[j], r[j + 1])
        for j in range(len(c)):
            mi2[c[j]] = min(mi2[c[j]], l[j], r[j + 1], mi2[i])
    ans0 = -inf
    for i in range(1, n + 1):
        c = [child[j] for j in range(s1[i], s1[i + 1])]
        x = [dp1[j] for j in c] + [inf]
        if i ^ 1:
            x += [dp2[i]]
        x.sort()
        ans1 = x[0] + 1
        y = [mi1[j] for j in c]
        if i ^ 1:
            y += [mi2[i]]
        ans1 = min(x[0] + 1, x[1], min(y))
        ans0 = max(ans0, ans1)
    ans.append(ans0)
sys.stdout.write('\n'.join(map(str, ans)))

Solution (Python):
import sys
input = lambda : sys.stdin.readline().rstrip()
INF = 10 ** 9

def solve():
    n = int(input())
    G = [[] for _ in range(n)]
    for _ in range(n - 1):
        (u, v) = [int(x) - 1 for x in input().split()]
        G[u].append(v)
        G[v].append(u)

    def dfs(root):
        par = [-1] * n
        id = [-1] * n
        ln = [-1] * n
        ans = INF
        vrt = -1
        S = [~root, root]
        while S:
            u = S.pop()
            if u >= 0:
                for v in G[u]:
                    if v != par[u]:
                        par[v] = u
                        S.append(~v)
                        S.append(v)
            else:
                u = ~u
                mn = INF
                child = -1
                for v in G[u]:
                    if v != par[u] and ln[v] < mn:
                        mn = ln[v]
                        child = v
                if child == -1:
                    id[u] = u
                    ln[u] = 1
                    continue
                for v in G[u]:
                    if v != par[u] and v != child and (ln[v] < ans):
                        ans = ln[v]
                        vrt = id[v]
                ln[u] = mn + 1
                id[u] = id[child]
                if u == root and ln[u] < ans:
                    ans = ln[u]
                    vrt = id[u]
        return (ans, vrt)
    ans = 0
    root = 0
    for _ in range(3):
        (x, new_root) = dfs(root)
        ans = max(ans, x)
        if new_root != root:
            root = new_root
        else:
            break
    return ans
out = []
for _ in range(int(input())):
    out.append(solve())
print('\n'.join(map(str, out)))