結果

問題 No.3442 Good Vertex Connectivity
コンテスト
ユーザー 👑 potato167
提出日時 2026-02-03 15:39:50
言語 C++17
(gcc 15.2.0 + boost 1.89.0)
結果
RE  
実行時間 -
コード長 6,010 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 2,761 ms
コンパイル使用メモリ 234,696 KB
実行使用メモリ 42,292 KB
最終ジャッジ日時 2026-02-06 20:55:29
合計ジャッジ時間 47,921 ms
ジャッジサーバーID
(参考情報)
judge2 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample RE * 1
other AC * 4 RE * 65
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
using namespace std;
#include <atcoder/segtree>

namespace po167{
template<class T, T(*op)(T, T)>
struct Sparse_table{
    int n;
    int depth;
    std::vector<std::vector<T>> val;
    void init(std::vector<T> &v){
        depth = 1;
        n = v.size();
        while ((1 << depth) <= n) depth++;
        val.resize(depth);
        val[0] = v;
        for (int i = 1; i < depth; i++){
            val[i].resize(n);
            for (int j = 0; j <= n - (1 << i); j++){
                val[i][j] = op(val[i - 1][j], val[i - 1][j + (1 << (i - 1))]);
            }
        }
    }
    Sparse_table(std::vector<T> v){
        init(v);
    }
    Sparse_table(){}
    // 0 <= l < r <= n
    // if l == r : assert
    T prod(int l, int r){
        assert(0 <= l && l < r && r <= n);
        int z=31-__builtin_clz(r-l);
        return op(val[z][l], val[z][r - (1 << z)]);
    }
};
}

namespace po167{
int op(int a, int b){
    return std::min(a, b);
}
struct LCA{
    Sparse_table<int, op> table;
    std::vector<int> depth;
    std::vector<int> E;
    std::vector<int> order;
    int var_num;
    void init(std::vector<std::vector<int>> &g, int root = 0){
        var_num = g.size();
        assert(0 <= root && root < var_num);
        std::vector<int> val;
        depth.assign(var_num, -1);
        depth[root] = 0;
        E.resize(var_num);
        std::vector<int> tmp;
        order.clear();
        tmp.reserve(var_num);
        order.reserve(var_num);
        int c = 0;
        auto dfs = [&](auto self, int var, int pare) -> void {
            E[var] = c++;
            if (var != root) tmp.push_back(E[pare]);
            order.push_back(var);
            for (auto x : g[var]) if (depth[x] == -1){
                depth[x] = depth[var] + 1;
                self(self, x, var);
            }
        };
        dfs(dfs, root, -1);
        assert(c == var_num);
        table.init(tmp);
    }
    void init(std::vector<int> &pare){
        int root = -1;
        int n = pare.size();
        std::vector<std::vector<int>> g(n);
        for (int i = 0; i < n; i++){
            if (pare[i] < 0){
                assert(root == -1);
                root = i;
            }
            else{
                assert(0 <= pare[i] && pare[i] < n);
                g[pare[i]].push_back(i);
            }
        }
        assert(root != -1);
        init(g, root);
    }
    LCA (std::vector<std::vector<int>> g, int root = 0){
        init(g, root);
    }
    LCA (std::vector<int> pare){
        init(pare);
    }
    LCA(){
        
    }
    int lca(int a, int b){
        assert(0 <= std::min(a, b) && std::max(a, b) < var_num);
        if (a == b) return a;
        if (E[a] > E[b]) std::swap(a, b);
        return order[table.prod(E[a], E[b])];
    }
    int dist(int a, int b){
        assert(0 <= std::min(a, b) && std::max(a, b) < var_num);
        return depth[a] + depth[b] - 2 * depth[lca(a, b)];
    }
    int back(int var, int len){
        assert(len <= depth[var]);
        if (len == 0) return var;
        int l = 0, r = E[var];
        while (r - l > 1){
            int m = (l + r) / 2;
            if (depth[var] - depth[order[table.prod(m, E[var])]] < len){
                r = m;
            }
            else l = m;
        }
        return order[table.prod(l, E[var])];
    }
    // a -> b
    int jump(int a, int b, int len){
        int c = lca(a, b);
        if (len <= depth[a] - depth[c]) return back(a, len);
        len -= depth[a] - depth[c];
        if (len <= depth[b] - depth[c]) return back(b, depth[b] - depth[c] - len);
        return -1;
    }
};

}

po167::LCA lca;

struct F{
    int l = -1;
    int r = -1;
    int ans = 0;
};

F op(F l, F r){
    if (l.l == -1) return r;
    if (r.r == -1) return l;
    l.ans += r.ans;
    l.ans += lca.dist(l.r, r.l);
    l.r = r.r;
    return l;
}
F e(){
    return F{};
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int N;
    cin >> N;
    vector<vector<int>> G(N);
    for (int i = 0; i < N - 1; i++){
        int a, b;
        cin >> a >> b;
        a--, b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    lca.init(G);
    vector<int> L(N), R(N);
    {
        int tmp = 0;
        auto dfs = [&](auto self, int var, int par) -> void {
            L[var] = tmp;
            tmp++;
            for (auto x : G[var]) if (x != par){
                    self(self, x, var);
                }
            R[var] = tmp;
        };
        dfs(dfs, 0, -1);
    }
    vector<int> p(N);
    atcoder::segtree<F, op, e> seg(N);
    for (int i = 0; i < N; i++){
        cin >> p[i];
        if (p[i]){
            seg.set(L[i], {i, i, 0});
        }
    }
    int Q;
    cin >> Q;
    while (Q--){
        int t;
        cin >> t;
        // 変更クエリ
        if (t == 1){
            int var;
            cin >> var;
            var--;
            p[var] ^= 1;
            if (p[var]){
                seg.set(L[var], {var, var, 0});
            }
            else{
                seg.set(L[var], e());
            }
        }
        // 出力クエリ
        if (t == 2){
            int x, y;
            cin >> x >> y;
            x--, y--;
            F tmp;
            // x == y のとき
            if (x == y){
            	assert(false);
                tmp = seg.all_prod();
            }
            // y の部分木内に x が存在するとき
            else if (L[y] < L[x] && L[x] < R[y]){
                // x から y へ行き、その 1 つ前の頂点を考える
                int z = lca.jump(y, x, 1);
                tmp = op(seg.prod(0, L[z]), seg.prod(R[z], N));
            }
            // そうでないとき
            else{
                tmp = seg.prod(L[y], R[y]);
            }
            if (tmp.l == -1){
                tmp.ans = -2;
            }
            else{
                tmp.ans += lca.dist(tmp.l, tmp.r);
            }
            cout << 1 + tmp.ans / 2 << "\n";
        }
    }
}
0