Educational Codeforces Round 25: G. Tree Queries

http://codeforces.com/contest/825/problem/G

解法

f:id:pekempey:20170717205714p:plain

一番最初の黒頂点を根 r として考える。黒頂点に囲まれている部分を black-tree と呼ぶことにする。

タイプ1
u-r パスを black-tree に併合すればいい。事前に r-u パス上の最小頂点を求めておくことで O(1) で併合と同等の操作が行える。

タイプ2
white-path と black-tree の最小値を求めれば良い。white-path を厳密に求める必要はなく、r-u パス上の最小頂点のみを求めれば良い。これも O(1) でできる。

#include <iostream>
#include <algorithm>
#include <vector>

int input() {
    int n;
    scanf("%d", &n);
    return n;
}

int main() {
    int n, q;
    std::cin >> n >> q;

    std::vector<std::vector<int>> g(n);
    for (int i = 0; i < n - 1; i++) {
        int u = input() - 1;
        int v = input() - 1;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    input();
    int root = input() % n;
    q--;

    std::vector<int> white_path(n, -1);
    std::vector<int> stack;
    white_path[root] = root;

    stack.push_back(root);
    while (!stack.empty()) {
        const int u = stack.back();
        stack.pop_back();
        white_path[u] = std::min(u, white_path[u]);

        for (int v : g[u]) {
            if (white_path[v] == -1) {
                white_path[v] = white_path[u];
                stack.push_back(v);
            }
        }
    }

    int ans = 0;
    int black_min = 1e9;
    while (q--) {
        int t = input();
        int x = (input() + ans) % n;

        if (t == 1) {
            black_min = std::min(black_min, white_path[x]);
        } else {
            ans = std::min(white_path[x], black_min) + 1;
            printf("%d\n", ans);
        }
    }
}