Submission #1307949

#TimeUsernameProblemLanguageResultExecution timeMemory
1307949vk3601hSynchronization (JOI13_synchronization)C++20
100 / 100
276 ms32320 KiB
#include <bits/stdc++.h>
using namespace std;

template <typename _Tp>
class SumSegmentTree{
private:
    int size;
    vector<_Tp> segtree;
    vector<_Tp> lazy;

    void apply(int at, int at_left, int at_right, _Tp val){
        segtree[at] += (at_right - at_left + 1) * val;
        lazy[at] += val;
    }

    void push_down(int at, int at_left, int at_right){
        if (at_left < at_right && lazy[at] != 0){
            int mid = (at_left + at_right) / 2;
            apply(2 * at, at_left, mid, lazy[at]);
            apply(2 * at + 1, mid + 1, at_right, lazy[at]);
            lazy[at] = 0;
        }
    }

    void build(const _Tp DEFAULT, int at, int at_left, int at_right){
        if (at_left == at_right){
            segtree[at] = DEFAULT;
            return;
        }

        int mid = (at_left + at_right) / 2;
        build(DEFAULT, 2 * at, at_left, mid);
        build(DEFAULT, 2 * at + 1, mid + 1, at_right);
        segtree[at] = segtree[2 * at] + segtree[2 * at + 1];
    }

    void node_add(int ind, _Tp val, int at, int at_left, int at_right){
        if (at_left == at_right){
            apply(at, at_left, at_right, val);
            return;
        }
        push_down(at, at_left, at_right);

        int mid = (at_left + at_right) / 2;
        if (ind <= mid) node_add(ind, val, 2 * at, at_left, mid);
        else node_add(ind, val, 2 * at + 1, mid + 1, at_right);
        segtree[at] = segtree[2 * at] + segtree[2 * at + 1];
    }

    void range_add(int start, int end, _Tp val, int at, int at_left, int at_right){
        if (end < at_left || at_right < start) return;
        if (start <= at_left && at_right <= end){
            apply(at, at_left, at_right, val);
            return;
        }
        push_down(at, at_left, at_right);

        int mid = (at_left + at_right) / 2;
        range_add(start, end, val, 2 * at, at_left, mid);
        range_add(start, end, val, 2 * at + 1, mid + 1, at_right);
        segtree[at] = segtree[2 * at] + segtree[2 * at + 1];
    }

    _Tp query(int ind, int at, int at_left, int at_right){
        if (at_left == at_right) return segtree[at];
        push_down(at, at_left, at_right);

        int mid = (at_left + at_right) / 2;
        if (ind <= mid) return query(ind, 2 * at, at_left, mid);
        return query(ind, 2 * at + 1, mid + 1, at_right);
    }

public:
    SumSegmentTree(int _size, const _Tp DEFAULT = 1) : size(_size), segtree(size * 4), lazy(size * 4, 0) {
        build(DEFAULT, 1, 0, size - 1);
    }

    void node_add(int ind, _Tp val) {node_add(ind, val, 1, 0, size - 1);}

    void range_add(int start, int end, _Tp val) {range_add(start, end, val, 1, 0, size - 1);}

    _Tp query(int ind) {return query(ind, 1, 0, size - 1);}
};

template <typename _Tp>
class MaxSegmentTree{
private:
    int size;
    vector<_Tp> segtree;

    void build(int at, int at_left, int at_right){
        if (at_left == at_right){
            segtree[at] = at_left;
            return;
        }

        int mid = (at_left + at_right) / 2;
        build(2 * at, at_left, mid);
        build(2 * at + 1, mid + 1, at_right);
        segtree[at] = max(segtree[2 * at], segtree[2 * at + 1]);
    }

    void modify(int ind, _Tp val, int at, int at_left, int at_right){
        if (at_left == at_right){
            segtree[at] = val;
            return;
        }

        int mid = (at_left + at_right) / 2;
        if (ind <= mid) modify(ind, val, 2 * at, at_left, mid);
        else modify(ind, val, 2 * at + 1, mid + 1, at_right);
        segtree[at] = max(segtree[2 * at], segtree[2 * at + 1]);
    }

    _Tp query(int start, int end, int at, int at_left, int at_right){
        if (end < at_left || at_right < start) return -1;
        if (start <= at_left && at_right <= end) return segtree[at];

        int mid = (at_left + at_right) / 2;
        return max(query(start, end, 2 * at, at_left, mid), query(start, end, 2 * at + 1, mid + 1, at_right));
    }

public:
    MaxSegmentTree(int _size) : size(_size), segtree(size * 4) {
        build(1, 0, size - 1);
    }

    void modify(int ind, _Tp val) {modify(ind, val, 1, 0, size - 1);}

    _Tp query(int start, int end) {return query(start, end, 1, 0, size - 1);}
};

class Solver{
private:
    const vector<vector<int>> &adj;
    vector<int> parent, depth, heavy, head, pos, old;
    SumSegmentTree<int> segtree;
    MaxSegmentTree<int> top;

    int dfs(int curr){
        int size = 1, max_c_size = 0;
        for (int child : adj[curr]){
            if (child != parent[curr]){
                parent[child] = curr;
                depth[child] = depth[curr] + 1;

                int c_size = dfs(child);
                size += c_size;
                if (c_size > max_c_size){
                    max_c_size = c_size;
                    heavy[curr] = child;
                }
            }
        }
        return size;
    }

    void decompose(int curr, int curr_head, int &timer){
        head[curr] = curr_head;
        pos[curr] = timer;
        timer++;

        if (heavy[curr] != -1) decompose(heavy[curr], curr_head, timer);
        for (int child : adj[curr]) if (child != parent[curr] && child != heavy[curr]) decompose(child, child, timer);
    }

public:
    Solver(const vector<vector<int>> &_adj) : adj(_adj), parent(adj.size()), depth(adj.size()), heavy(adj.size(), -1), head(adj.size()), pos(adj.size()), old(adj.size(), 0), segtree(adj.size()), top(adj.size()) {
        parent[0] = -1;
        depth[0] = 0;
        dfs(0);

        int timer = 0;
        decompose(0, 0, timer);
    }

    void connect(int u, int v){
        if (depth[u] > depth[v]) swap(u, v);
        top.modify(pos[v], -1);

        int curr = u, contrib = segtree.query(pos[v]) - old[v];
        while (curr >= 0){
            int curr_top = top.query(pos[head[curr]], pos[curr]);
            segtree.range_add((curr_top == -1 ? pos[head[curr]] : curr_top), pos[curr], contrib);
            if (curr_top != -1) break;
            curr = parent[head[curr]];
        }
    }

    void disconnect(int u, int v){
        if (depth[u] > depth[v]) swap(u, v);
        top.modify(pos[v], pos[v]);

        int curr = u;
        while (curr >= 0){
            int curr_top = top.query(pos[head[curr]], pos[curr]);
            if (curr_top >= 0){
                curr = curr_top;
                break;
            }
            curr = parent[head[curr]];
        }

        int contrib = segtree.query(curr) - segtree.query(pos[v]);
        segtree.node_add(pos[v], contrib);
        old[v] = segtree.query(pos[v]);
    }

    int query(int node){
        int curr = node;
        while (curr >= 0){
            int curr_top = top.query(pos[head[curr]], pos[curr]);
            if (curr_top >= 0){
                curr = curr_top;
                break;
            }
            curr = parent[head[curr]];
        }
        return segtree.query(curr);
    }
};

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

    int node_num, op_num, query_num;
    cin >> node_num >> op_num >> query_num;

    vector<pair<int, int>> edges(node_num - 1);
    vector<vector<int>> adj(node_num);
    for (int i = 0; i < node_num - 1; i++){
        int u, v;
        cin >> u >> v;
        u--, v--;
        edges[i] = {u, v};
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    Solver solver(adj);

    vector<bool> state(node_num - 1, false);
    while (op_num--){
        int ind;
        cin >> ind;
        ind--;

        if (!state[ind]){
            solver.connect(edges[ind].first, edges[ind].second);
            state[ind] = true;
        }
        else {
            solver.disconnect(edges[ind].first, edges[ind].second);
            state[ind] = false;
        }
    }

    while (query_num--){
        int node;
        cin >> node;
        cout << solver.query(node - 1) << "\n";
    }

    return 0;
}
#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...