Perfect Matching (Codeforces 1633F)
Tags: Others, divide and conquer

You are given a tree consisting of $$$n$$$ vertices (numbered from $$$1$$$ to $$$n$$$) and $$$n-1$$$ edges (numbered from $$$1$$$ to $$$n-1$$$). Initially, all vertices except vertex $$$1$$$ are inactive.You have to process queries of three types:  $$$1$$$ $$$v$$$ — activate the vertex $$$v$$$. It is guaranteed that the vertex $$$v$$$ is inactive before this query, and one of its neighbors is active. After activating the vertex, you have to choose a subset of edges of the tree such that each active vertex is incident to exactly one chosen edge, and each inactive vertex is not incident to any of the chosen edges — in other words, this subset should represent a perfect matching on the active part of the tree. If any such subset of edges exists, print the sum of indices of edges in it; otherwise, print $$$0$$$.  $$$2$$$ — queries of this type will be asked only right after a query of type $$$1$$$, and there will be at most $$$10$$$ such queries. If your answer to the previous query was $$$0$$$, simply print $$$0$$$; otherwise, print the subset of edges for the previous query as follows: first, print the number of edges in the subset, then print the indices of the chosen edges in ascending order. The sum of indices should be equal to your answer to the previous query.  $$$3$$$ — terminate the program. Note that you should solve the problem in online mode. It means that you can't read the whole input at once. You can read each query only after writing the answer for the last query. Use functions fflush in C++ and BufferedWriter.flush in Java languages after each writing in your program.

Input: The first line contains one integer $$$n$$$ ($$$2 \le n \le 2 \cdot 10^5$$$) — the number of vertices of the tree.Then $$$n-1$$$ lines follow. The $$$i$$$-th line contains two integers $$$u_i$$$ and $$$v_i$$$ ($$$1 \le u_i, v_i \le n$$$; $$$u_i \ne v_i$$$) — the endpoints of the $$$i$$$-th edge. These edges form a tree.Then the queries follow in the format described in the statement, one line per query. There will be at least $$$2$$$ and at most $$$n+10$$$ queries. The last query (and only the last one) will be of type $$$3$$$. Note that you can read the $$$i$$$-th query only if you have already given the answer for the query $$$i-1$$$ (except for $$$i = 1$$$).If your answer for one of the queries is incorrect and the judging program recognizes it, instead of the next query, you may receive the integer $$$0$$$ on a separate line. After receiving it, your program should terminate gracefully, and you will receive "Wrong Answer" verdict. If your program doesn't terminate, your solution may receive some other verdict, like "Time Limit Exceeded", "Idleness Limit Exceeded", etc. Note that the fact that your solution doesn't receive the integer $$$0$$$, it does not mean that all your answers are correct, some of them will be checked only after your program is terminated.

Output: For each query of type $$$1$$$ or $$$2$$$, print the answer on a separate line as described in the statement. Don't forget to flush the output.


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

Sample Outputs:
1
1 1
0
0
4
2 1 3
0
0
0

Solution (Python):
import sys, os
input = sys.stdin.buffer.readline

def make_graph(n, m):
    (x, y, s) = ([0] * (2 * m), [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)
        (y[i], y[i + 1]) = ((i >> 1) + 1, (i >> 1) + 1)
    for i in range(3, n + 3):
        s[i] += s[i - 1]
    (G, W) = ([0] * (2 * m), [0] * (2 * m))
    for i in range(2 * m):
        j = x[i] + 1
        G[s[j]] = x[i ^ 1]
        W[s[j]] = y[i ^ 1]
        s[j] += 1
    return (G, W, s)

def bfs(s):
    q = [s]
    dist = [inf] * (n + 1)
    dist[s] = 0
    parent = [-1] * (n + 1)
    w = [0] * (n + 1)
    for i in q:
        di = dist[i]
        for v in range(s0[i], s0[i + 1]):
            j = G[v]
            if dist[j] == inf:
                q.append(j)
                dist[j] = di + 1
                parent[j] = i
                w[j] = W[v]
    return (q, dist, parent, w)

def f(i):
    if not lazy[i]:
        return
    (tree1[i], tree1[i ^ l2]) = (tree1[i ^ l2], tree1[i])
    (tree2[i], tree2[i ^ l2]) = (tree2[i ^ l2], tree2[i])
    if i < l1:
        lazy[i << 1] ^= 1
        lazy[i << 1 ^ 1] ^= 1
    lazy[i] = 0
    return

def update(s, t, x):
    q = [1]
    for j in q:
        (l0, r0) = (ll[j], rr[j])
        if s <= l0 and r0 <= t:
            lazy[j] ^= x
            f(j)
            continue
        f(j)
        m0 = l0 + r0 >> 1
        if s <= m0 and l0 <= t:
            q.append(j << 1)
        if s <= r0 and m0 + 1 <= t:
            q.append(j << 1 ^ 1)
    for i in q[::-1]:
        if i < l1:
            (j, k) = (i << 1, i << 1 ^ 1)
            f(j)
            f(k)
            tree1[i] = tree1[j] + tree1[k]
            tree1[i ^ l2] = tree1[j ^ l2] + tree1[k ^ l2]
            tree2[i] = tree2[j] + tree2[k]
            tree2[i ^ l2] = tree2[j ^ l2] + tree2[k ^ l2]
    return
n = int(input())
(G, W, s0) = make_graph(n, n - 1)
inf = pow(10, 9) + 1
(p, dist, parent, w) = bfs(1)
cnt = [1] * (n + 1)
for i in p[::-1][:-1]:
    cnt[parent[i]] += cnt[i]
x = [i for i in range(n + 1)]
for i in p:
    (j, ma, di) = (i, -1, dist[i])
    for v in range(s0[i], s0[i + 1]):
        k = G[v]
        if dist[k] < di:
            continue
        if ma < cnt[k]:
            (j, ma) = (k, cnt[k])
    x[j] = x[i]
y = [0] * (n + 1)
visit = [0] * (n + 1)
c = 0
for i in p[::-1]:
    if visit[i]:
        continue
    j = i
    while j ^ x[j]:
        visit[j] = 1
        y[j] = c
        c += 1
        j = parent[j]
    visit[j] = 1
    y[j] = c
    c += 1
l1 = pow(2, (n + 1).bit_length())
l2 = 2 * l1
(ll, rr) = ([0] * l2, [0] * l2)
(ll[1], rr[1]) = (0, l1 - 1)
for i in range(1, l1):
    (ll[2 * i], rr[2 * i + 1]) = (ll[i], rr[i])
    m = ll[i] + rr[i] >> 1
    (ll[2 * i + 1], rr[2 * i]) = (m + 1, m)
tree1 = [0] * (2 * l2)
tree2 = [0] * (2 * l2)
for i in range(2, n + 1):
    j = y[i]
    (tree1[j ^ l1 ^ l2], tree2[j ^ l1 ^ l2]) = (w[i], 1)
for i in range(l1 - 1, 0, -1):
    tree1[i ^ l2] = tree1[2 * i ^ l2] + tree1[2 * i + 1 ^ l2]
    tree2[i ^ l2] = tree2[2 * i ^ l2] + tree2[2 * i + 1 ^ l2]
lazy = [0] * l2
(now, s) = ([0] * (n + 1), 1)
now[1] = 1
while True:
    t = list(map(int, input().split()))
    if t[0] == 1:
        v = t[1]
        now[v] = 1
        s += 1
        while v ^ -1:
            u = x[v]
            update(y[v], y[u], 1)
            v = parent[u]
        ans = 0 if 2 * tree2[1] ^ s else tree1[1]
        os.write(1, b'%d\n' % ans)
    elif t[0] == 2:
        if not ans:
            ans = [0]
        else:
            ans = [0] * (s // 2)
            (ok, j) = (list(now), 0)
            for i in p[::-1]:
                if not ok[i]:
                    continue
                ok[parent[i]] = 0
                ans[j] = w[i]
                j += 1
            ans = [s // 2] + sorted(ans)
        os.write(1, b'%s\n' % ' '.join(map(str, ans)).encode())
    else:
        exit()

Solution (Python):
import sys, os
input = sys.stdin.buffer.readline

def make_graph(n, m):
    (x, y, s) = ([0] * (2 * m), [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)
        (y[i], y[i + 1]) = ((i >> 1) + 1, (i >> 1) + 1)
    for i in range(3, n + 3):
        s[i] += s[i - 1]
    (G, W) = ([0] * (2 * m), [0] * (2 * m))
    for i in range(2 * m):
        j = x[i] + 1
        G[s[j]] = x[i ^ 1]
        W[s[j]] = y[i ^ 1]
        s[j] += 1
    return (G, W, s)

def bfs(s):
    q = [s]
    dist = [inf] * (n + 1)
    dist[s] = 0
    parent = [-1] * (n + 1)
    w = [0] * (n + 1)
    for i in q:
        di = dist[i]
        for v in range(s0[i], s0[i + 1]):
            j = G[v]
            if dist[j] == inf:
                q.append(j)
                dist[j] = di + 1
                parent[j] = i
                w[j] = W[v]
    return (q, dist, parent, w)

def f(i):
    if not lazy[i]:
        return
    (tree1[i], tree1[i ^ l2]) = (tree1[i ^ l2], tree1[i])
    (tree2[i], tree2[i ^ l2]) = (tree2[i ^ l2], tree2[i])
    if i < l1:
        lazy[i << 1] ^= 1
        lazy[i << 1 ^ 1] ^= 1
    lazy[i] = 0
    return

def update(s, t, x):
    q = [1]
    for j in q:
        (l0, r0) = (ll[j], rr[j])
        if s <= l0 and r0 <= t:
            lazy[j] ^= x
            f(j)
            continue
        f(j)
        m0 = l0 + r0 >> 1
        if s <= m0 and l0 <= t:
            q.append(j << 1)
        if s <= r0 and m0 + 1 <= t:
            q.append(j << 1 ^ 1)
    for i in q[::-1]:
        if i < l1:
            (j, k) = (i << 1, i << 1 ^ 1)
            f(j)
            f(k)
            tree1[i] = tree1[j] + tree1[k]
            tree1[i ^ l2] = tree1[j ^ l2] + tree1[k ^ l2]
            tree2[i] = tree2[j] + tree2[k]
            tree2[i ^ l2] = tree2[j ^ l2] + tree2[k ^ l2]
    return
n = int(input())
(G, W, s0) = make_graph(n, n - 1)
inf = pow(10, 9) + 1
(p, dist, parent, w) = bfs(1)
cnt = [1] * (n + 1)
for i in p[::-1][:-1]:
    cnt[parent[i]] += cnt[i]
x = [i for i in range(n + 1)]
for i in p:
    (j, ma, di) = (i, -1, dist[i])
    for v in range(s0[i], s0[i + 1]):
        k = G[v]
        if dist[k] < di:
            continue
        if ma < cnt[k]:
            (j, ma) = (k, cnt[k])
    x[j] = x[i]
y = [0] * (n + 1)
visit = [0] * (n + 1)
c = 0
for i in p[::-1]:
    if visit[i]:
        continue
    j = i
    while j ^ x[j]:
        visit[j] = 1
        y[j] = c
        c += 1
        j = parent[j]
    visit[j] = 1
    y[j] = c
    c += 1
l1 = pow(2, (n + 1).bit_length())
l2 = 2 * l1
(ll, rr) = ([0] * l2, [0] * l2)
(ll[1], rr[1]) = (0, l1 - 1)
for i in range(1, l1):
    (ll[2 * i], rr[2 * i + 1]) = (ll[i], rr[i])
    m = ll[i] + rr[i] >> 1
    (ll[2 * i + 1], rr[2 * i]) = (m + 1, m)
tree1 = [0] * (2 * l2)
tree2 = [0] * (2 * l2)
for i in range(2, n + 1):
    j = y[i]
    (tree1[j ^ l1 ^ l2], tree2[j ^ l1 ^ l2]) = (w[i], 1)
for i in range(l1 - 1, 0, -1):
    tree1[i ^ l2] = tree1[2 * i ^ l2] + tree1[2 * i + 1 ^ l2]
    tree2[i ^ l2] = tree2[2 * i ^ l2] + tree2[2 * i + 1 ^ l2]
lazy = [0] * l2
(now, s) = ([0] * (n + 1), 1)
now[1] = 1
while True:
    t = list(map(int, input().split()))
    if t[0] == 1:
        v = t[1]
        now[v] = 1
        s += 1
        while v ^ -1:
            u = x[v]
            update(y[v], y[u], 1)
            v = parent[u]
        ans = 0 if 2 * tree2[1] ^ s else tree1[1]
        os.write(1, b'%d\n' % ans)
    elif t[0] == 2:
        if not ans:
            ans = [0]
        else:
            ans = [0] * (s // 2)
            (ok, j) = (list(now), 0)
            for i in p[::-1]:
                if not ok[i]:
                    continue
                ok[parent[i]] = 0
                ans[j] = w[i]
                j += 1
            ans = [s // 2] + sorted(ans)
        os.write(1, b'%s\n' % ' '.join(map(str, ans)).encode())
    else:
        exit()

Solution (Python):
import sys, os
input = sys.stdin.buffer.readline

def make_graph(n, m):
    (x, y, s) = ([0] * (2 * m), [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)
        (y[i], y[i + 1]) = ((i >> 1) + 1, (i >> 1) + 1)
    for i in range(3, n + 3):
        s[i] += s[i - 1]
    (G, W) = ([0] * (2 * m), [0] * (2 * m))
    for i in range(2 * m):
        j = x[i] + 1
        G[s[j]] = x[i ^ 1]
        W[s[j]] = y[i ^ 1]
        s[j] += 1
    return (G, W, s)

def bfs(s):
    q = [s]
    dist = [inf] * (n + 1)
    dist[s] = 0
    parent = [-1] * (n + 1)
    w = [0] * (n + 1)
    for i in q:
        di = dist[i]
        for v in range(s0[i], s0[i + 1]):
            j = G[v]
            if dist[j] == inf:
                q.append(j)
                dist[j] = di + 1
                parent[j] = i
                w[j] = W[v]
    return (q, dist, parent, w)

def f(i):
    if not lazy[i]:
        return
    (tree1[i], tree1[i ^ l2]) = (tree1[i ^ l2], tree1[i])
    (tree2[i], tree2[i ^ l2]) = (tree2[i ^ l2], tree2[i])
    if i < l1:
        lazy[i << 1] ^= 1
        lazy[i << 1 ^ 1] ^= 1
    lazy[i] = 0
    return

def update(s, t, x):
    q = [1]
    for j in q:
        (l0, r0) = (ll[j], rr[j])
        if s <= l0 and r0 <= t:
            lazy[j] ^= x
            f(j)
            continue
        f(j)
        m0 = l0 + r0 >> 1
        if s <= m0 and l0 <= t:
            q.append(j << 1)
        if s <= r0 and m0 + 1 <= t:
            q.append(j << 1 ^ 1)
    for i in q[::-1]:
        if i < l1:
            (j, k) = (i << 1, i << 1 ^ 1)
            f(j)
            f(k)
            tree1[i] = tree1[j] + tree1[k]
            tree1[i ^ l2] = tree1[j ^ l2] + tree1[k ^ l2]
            tree2[i] = tree2[j] + tree2[k]
            tree2[i ^ l2] = tree2[j ^ l2] + tree2[k ^ l2]
    return
n = int(input())
(G, W, s0) = make_graph(n, n - 1)
inf = pow(10, 9) + 1
(p, dist, parent, w) = bfs(1)
cnt = [1] * (n + 1)
for i in p[::-1][:-1]:
    cnt[parent[i]] += cnt[i]
x = [i for i in range(n + 1)]
for i in p:
    (j, ma, di) = (i, -1, dist[i])
    for v in range(s0[i], s0[i + 1]):
        k = G[v]
        if dist[k] < di:
            continue
        if ma < cnt[k]:
            (j, ma) = (k, cnt[k])
    x[j] = x[i]
y = [0] * (n + 1)
visit = [0] * (n + 1)
c = 0
for i in p[::-1]:
    if visit[i]:
        continue
    j = i
    while j ^ x[j]:
        visit[j] = 1
        y[j] = c
        c += 1
        j = parent[j]
    visit[j] = 1
    y[j] = c
    c += 1
l1 = pow(2, (n + 1).bit_length())
l2 = 2 * l1
(ll, rr) = ([0] * l2, [0] * l2)
(ll[1], rr[1]) = (0, l1 - 1)
for i in range(1, l1):
    (ll[2 * i], rr[2 * i + 1]) = (ll[i], rr[i])
    m = ll[i] + rr[i] >> 1
    (ll[2 * i + 1], rr[2 * i]) = (m + 1, m)
tree1 = [0] * (2 * l2)
tree2 = [0] * (2 * l2)
for i in range(2, n + 1):
    j = y[i]
    (tree1[j ^ l1 ^ l2], tree2[j ^ l1 ^ l2]) = (w[i], 1)
for i in range(l1 - 1, 0, -1):
    tree1[i ^ l2] = tree1[2 * i ^ l2] + tree1[2 * i + 1 ^ l2]
    tree2[i ^ l2] = tree2[2 * i ^ l2] + tree2[2 * i + 1 ^ l2]
lazy = [0] * l2
(now, s) = ([0] * (n + 1), 1)
now[1] = 1
while True:
    t = list(map(int, input().split()))
    if t[0] == 1:
        v = t[1]
        now[v] = 1
        s += 1
        while v ^ -1:
            u = x[v]
            update(y[v], y[u], 1)
            v = parent[u]
        ans = 0 if 2 * tree2[1] ^ s else tree1[1]
        os.write(1, b'%d\n' % ans)
    elif t[0] == 2:
        if not ans:
            ans = [0]
        else:
            ans = [0] * (s // 2)
            (ok, j) = (list(now), 0)
            for i in p[::-1]:
                if not ok[i]:
                    continue
                ok[parent[i]] = 0
                ans[j] = w[i]
                j += 1
            ans = [s // 2] + sorted(ans)
        os.write(1, b'%s\n' % ' '.join(map(str, ans)).encode())
    else:
        exit()