제출 #702354

#제출 시각아이디문제언어결과실행 시간메모리
702354CyanmondSpring cleaning (CEOI20_cleaning)C++17
100 / 100
546 ms29356 KiB
#include <bits/stdc++.h>

using i64 = long long;

struct HLD {
    int n;
    std::vector<std::vector<int>> tree;
    std::vector<int> st, in, out, head, parent;

    HLD(std::vector<std::vector<int>> tree_, int root) {
        tree = tree_;
        n = tree.size();
        st.resize(n);
        in.resize(n);
        out.resize(n);
        head.resize(n);
        parent.resize(n);
        dfs1(root, -1);
        int x = 0;
        head[root] = root;
        dfs2(root, -1, x);
    }

    void dfs1(int v, int p) {
        parent[v] = p;
        st[v] = 1;
        for (int &t : tree[v]) {
            if (t == p) {
                continue;
            }
            dfs1(t, v);
            st[v] += st[t];
            if (st[tree[v][0]] < st[t]) {
                std::swap(tree[v][0], t);
            }
        }
    }

    void dfs2(int v, int p, int &id) {
        in[v] = id++;
        for (const int t : tree[v]) {
            if (t == p) {
                continue;
            }
            head[t] = tree[v][0] == t ? head[v] : t;
            dfs2(t, v, id);
        }
        out[v] = id;
    }

    template <class F>
    void query(int v, const F &func) {
        while (v != -1) {
            func(in[head[v]], in[v] + 1);
            v = parent[head[v]];
        }
    }
};

struct node {
    int a, b;
};
node op(node a, node b) {
    return {a.a + b.a, a.b + b.b};
}
node e() {
    return {0, 0};
}
node map(bool x, node b) {
    if (x) std::swap(b.a, b.b);
    return b;
}
bool composite(bool x, bool y) {
    return x xor y;
}
bool id() {
    return false;
}
class lazySegtree {
    int n, size, lg;
    std::vector<node> data;
    std::vector<bool> lazy;

    void update(int i) {
        data[i] = op(data[2 * i], data[2 * i + 1]);
    }
    void cv(int i, bool f) {
        data[i] = map(f, data[i]);
        if (i < size) {
            lazy[i] = composite(f, lazy[i]);
        }
    }
    void push(int i) {
        cv(2 * i, lazy[i]);
        cv(2 * i + 1, lazy[i]);
        lazy[i] = id();
    }
    public:

    lazySegtree(int n_) {
        n = n_;
        size = 1;
        lg = 0;
        while (size < n) {
            ++lg;
            size *= 2;
        }
        data.assign(2 * size, e());
        lazy.assign(size, id());
    }

    void set(int i, node v) {
        i += size;
        for (int d = lg; d >= 1; --d) {
            push(i >> d);
        }
        data[i] = v;
        for (int d = 1; d <= lg; ++d) {
            update(i >> d);
        }
    }

    node fold(int l, int r) {
        l += size, r += size;
        for (int d = lg; d >= 1; --d) {
            if (((l >> d) << d) != l) push(l >> d);
            if (((r >> d) << d) != r) push((r - 1) >> d);
        }
        node retL = e(), retR = e();
        while (l < r) {
            if (l & 1) retL = op(retL, data[l++]);
            if (r & 1) retR = op(data[--r], retR);
            l /= 2;
            r /= 2;
        }
        return op(retL, retR);
    }

    void apply(int l, int r, bool f) {
        l += size, r += size;
        for (int d = lg; d >= 1; --d) {
            if (((l >> d) << d) != l) push(l >> d);
            if (((r >> d) << d) != r) push((r - 1) >> d);
        }
        int l2 = l, r2 = r;
        while (l < r) {
            if (l & 1) cv(l++, f);
            if (r & 1) cv(--r, f);
            l /= 2;
            r /= 2;
        }
        l = l2, r = r2;
        for (int d = 1; d <= lg; ++d) {
            if (((l >> d) << d) != l) update(l >> d);
            if (((r >> d) << d) != r) update((r - 1) >> d);
        }
    }
};

int main() {
    int N, Q;
    std::cin >> N >> Q;
    std::vector<int> A(N - 1), B(N - 1);
    std::vector<std::vector<int>> baseTree(N);
    for (int i = 0; i < N - 1; ++i) {
        std::cin >> A[i] >> B[i];
        --A[i], --B[i];
        baseTree[A[i]].push_back(B[i]);
        baseTree[B[i]].push_back(A[i]);
    }
    std::vector<int> D(Q);
    std::vector<std::vector<int>> L(Q);
    for (int i = 0; i < Q; ++i) {
        std::cin >> D[i];
        L[i].resize(D[i]);
        for (int &e : L[i]) {
            std::cin >> e;
            --e;
        }
    }
    std::vector<int> degree(N);
    for (int i = 0; i < N; ++i) {
        degree[i] = (int)baseTree[i].size();
    }
    const int nonLeafV = (std::max_element(degree.begin(), degree.end()) - degree.begin());
    const int countBaseLeaf = std::count(degree.begin(), degree.end(), 1);
    std::vector<bool> isEven(N);
    std::vector<int> parent(N);
    auto dfs = [&](auto &&self, const int v, const int p) -> bool {
        parent[v] = p;

        bool res = false;
        if (baseTree[v].size() == 1) {
            res = true;
        }
        for (const int t : baseTree[v]) {
            if (t == p) {
                continue;
            }
            res ^= self(self, t, v);
        }
        isEven[v] = not res;
        return res;
    };
    dfs(dfs, nonLeafV, -1);
    int baseAnswer = N - 1;

    HLD hld(baseTree, nonLeafV);
    lazySegtree seg(N);
    for (int i = 0; i < N; ++i) {
        node v = {isEven[i] ? 1 : 0, isEven[i] ? 0 : 1};
        seg.set(hld.in[i], v);
    }
    assert(seg.fold(1, N).a == std::count(isEven.begin(), isEven.end(), true) - isEven[nonLeafV]);

    for (int q = 0; q < Q; ++q) {
        int countLeaf = countBaseLeaf;
        int answer = baseAnswer;
        auto toup = [&](const int v) -> void {
            hld.query(v, [&](int l, int r) {
                seg.apply(l, r, true);
            });
        };

        for (int i = 0; i < D[q]; ++i) {
            const int v = L[q][i];
            if (degree[v] != 1) {
                ++countLeaf;
                ++answer;
                toup(v);
            } else {
                ++answer;
            }
            ++degree[v];
        }
        answer += seg.fold(1, N).a;
        if (countLeaf % 2 == 1) {
            answer = -1;
        }
        std::cout << answer << std::endl;

        for (int i = 0; i < D[q]; ++i) {
            const int v = L[q][i];
            --degree[v];
            if (degree[v] != 1) {
                toup(v);
            }
        }
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...