結果

問題 No.3442 Good Vertex Connectivity
コンテスト
ユーザー 👑 potato167
提出日時 2026-02-04 21:25:31
言語 C++17
(gcc 15.2.0 + boost 1.89.0)
結果
AC  
実行時間 1,291 ms / 3,000 ms
コード長 5,655 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,148 ms
コンパイル使用メモリ 234,620 KB
実行使用メモリ 30,408 KB
最終ジャッジ日時 2026-02-06 20:56:59
合計ジャッジ時間 46,064 ms
ジャッジサーバーID
(参考情報)
judge4 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1
other AC * 69
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

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

namespace po167{
    int op(int a, int b){
        return std::min(a, b);
    }
    int e(){
        return (1 << 30);
    }
    struct LCA{
        atcoder::segtree<int, op, e> seg;
        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);
            {
                atcoder::segtree<int, op, e> tmp2(tmp);
                seg = tmp2;
            }
        }
        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[seg.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[seg.prod(m, E[var])]] < len){
                    r = m;
                }
                else l = m;
            }
            return order[seg.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){
                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