Submission #1184741

#TimeUsernameProblemLanguageResultExecution timeMemory
1184741tin_leSynchronization (JOI13_synchronization)C++20
30 / 100
255 ms57720 KiB
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using pii = pair<int,int>;
using vi = vector<int>;
using vvi = vector<vi>;
using vpii = vector<pii>;
template<class T> using vt = vector<T>;

// ------------------- FW (Fenwick Tree) -----------------------
template<class T, typename F = function<T(const T&, const T&)>>
class FW {  
public: 
    int n, N;
    vt<T> root;    
    T DEFAULT;
    F func;
    FW() {}
    FW(int n, T DEFAULT, F func) : func(func) { 
        this->n = n;    
        this->DEFAULT = DEFAULT;
        N = floor(log2(n));
        root.resize(n, DEFAULT);
    }
    
    void update_at(int id, T val) {  
        assert(id >= 0);
        while(id < n) {    
            root[id] = func(root[id], val);
            id |= (id + 1);
        }
    }
    
    T get(int id) {   
        assert(id < n);
        T res = DEFAULT;
        while(id >= 0) { 
            res = func(res, root[id]);
            id = (id & (id + 1)) - 1;
        }
        return res;
    }

    T queries_range(int left, int right) {  
        if(left > right) return DEFAULT;
        return get(right) - (left - 1 >= 0 ? get(left - 1) : 0);
    }

    T queries_at(int i) {
        return queries_range(i, i);
    }

    // IMPORTANT: Use r+1 here because we assume BIT update is for [l, r] inclusive.
    void update_range(int l, int r, T val) {
        update_at(l, val);
        if(r + 1 < n)
            update_at(r + 1, -val);
    }
	
	void reset() {
		root.assign(n, DEFAULT);
	}

    int select(int x) { // get pos where prefix sum >= x
        int global = get(n - 1), curr = 0;
        for(int i = N; i >= 0; i--) {
            int t = curr ^ (1LL << i);
            if(t < n && global - root[t] >= x) {
                swap(curr, t);
                global -= root[curr];
            }
        }
        return curr + 1;
    }
};

// ------------------- LCA_O1 (LCA using Euler Tour & Sparse Table) -----------------------
template<typename T = int>
struct LCA_O1 {
    vector<int> enter;
    vpii euler;
    // Sparse Table
    vector<vector<pii>> st;
    vector<int> log_table;
    int timer;
    LCA_O1() {}
    LCA_O1(const vt<vt<T>> &graph, int root = 0) : timer(0) {
        int n = graph.size();
        enter.resize(n, -1);
        dfs(root, -1, 0, graph);
        int m = euler.size();
        log_table.resize(m + 1);
        for (int i = 2; i <= m; i++) log_table[i] = log_table[i / 2] + 1;
        int K = log_table[m] + 1;
        st.assign(K, vector<pii>(m));
        for (int i = 0; i < m; i++) st[0][i] = euler[i];
        for (int j = 1; j < K; j++) {
            for (int i = 0; i + (1 << j) <= m; i++) {
                pii a = st[j - 1][i], b = st[j - 1][i + (1 << (j - 1))];
                st[j][i] = (a.first < b.first ? a : b);
            }
        }
        // free euler if desired
    }
    void dfs(int node, int par, int d, const vt<vt<T>> &graph) {
        enter[node] = timer++;
        euler.push_back({d, node});
        for(auto nxt : graph[node]) {
            if(nxt == par) continue;
            dfs(nxt, node, d + 1, graph);
            euler.push_back({d, node});
            timer++;
        }
    }
    int lca(int u, int v) {
        int L = min(enter[u], enter[v]);
        int R = max(enter[u], enter[v]);
        int j = log_table[R - L + 1];
        pii a = st[j][L], b = st[j][R - (1 << j) + 1];
        return (a.first < b.first ? a : b).second;
    }
};

// ------------------- GRAPH Class -----------------------
template<typename T = int>
class GRAPH { 
public: 
    int n, m; 
    vvi dp;
    vi depth, parent, subtree;
    vi tin, tout, ord;
    int timer = 0;
    LCA_O1<T> lca_01;
    GRAPH() {}

    GRAPH(const vt<vt<T>>& graph, int root = 0) : lca_01(graph, root) {   
        n = graph.size();
        m = floor(log2(n)) + 1;
        dp.resize(n, vi(m, root)); // initialize dp entries to root
        depth.resize(n, 0);
        parent.resize(n, -1);
		subtree.resize(n, 1);
        tin.resize(n);
        tout.resize(n);
		ord.resize(n);
        dfs(graph, root, -1);
        init();
    }
    
    void dfs(const vt<vt<T>>& graph, int node, int par) {   
		tin[node] = timer++;
		ord[tin[node]] = node;
        for(auto nxt : graph[node]) {  
            if(nxt == par) continue;    
            depth[nxt] = depth[node] + 1;   
            dp[nxt][0] = node;
            parent[nxt] = node;
			dfs(graph, nxt, node);
			subtree[node] += subtree[nxt];
        }
		tout[node] = timer - 1;
    }

    bool isAncestor(int u, int v) { 
        return tin[u] <= tin[v] && tin[v] <= tout[u]; 
    }
    
    void init() {  
        for(int j = 1; j < m; j++) {   
            for(int i = 0; i < n; i++) {    
                dp[i][j] = dp[dp[i][j - 1]][j - 1];
            }
        }
    }
	
    int lca(int a, int b) { 
        return lca_01.lca(a, b);
    }
	
	int dist(int u, int v) {    
        int a = lca(u, v);  
        return depth[u] + depth[v] - 2 * depth[a];
    }

	int k_ancestor(int a, int k) {
        for(int i = m - 1; i >= 0; i--) {   
            if((k >> i) & 1) a = dp[a][i];
        }
        return a;
    }
};

// ------------------- Main solve() -----------------------
const int MK = 20;
void solve() {
    int n, m, q; 
    cin >> n >> m >> q;
    vpii edges(n - 1); // there are n-1 edges
    vvi graph(n);
    for(int i = 0; i < n - 1; i++) {
        int u, v; 
        cin >> u >> v;
        u--; v--; // convert to 0-index
        edges[i] = {u, v};
        graph[u].push_back(v);
        graph[v].push_back(u);
    }
    // Build GRAPH with root 0.
    GRAPH<int> g(graph, 0);
    // Reorient edges so that parent-child relationship is clear.
    for(int i = 0; i < n - 1; i++) {
        auto &e = edges[i];
        int u = e.first, v = e.second;
        if(g.parent[v] != u) swap(u, v);
        e = {u, v}; // now u is the parent, v is the child.
    }
    // Build a BIT (FW) with size = n (for Euler tour indices from 0 to n-1)
    FW<int> BITree(n, 0, [](const int &a, const int &b) { return a + b; });
    // Initialize BIT: for each node i, update at position tin[i] with +1.
    for (int i = 0; i < n; i++) {
        BITree.update_at(g.tin[i], 1);
    }
    
    // Lambda to find the representative parent using BIT values.
    auto find_par = [&](int u) -> int {
        int x = BITree.get(g.tin[u]);
        // Climb using binary lifting table dp.
        for (int j = MK - 1; j >= 0; j--) {
            int p = g.dp[u][j];
            // Avoid accessing if p is the same as u (or if dp[u][j] is out of bound)
            if(p < 0 || p >= n) continue;
            if(BITree.get(g.tin[p]) == x) {
                u = p;
            }
        }
        return u;
    };

    // used[] for edges toggling; initial ans[] is 1 for each node; del[] is auxiliary.
    vi used(n - 1, 0), ans(n, 1), del(n, 0);
    
    // Process m operations (edge toggles)
    while(m--) {
        int k; 
        cin >> k;
        k--; // convert edge id to 0-index
        auto &e = edges[k];
        int u = e.first, v = e.second;
        if(!used[k]) { // if edge is active, then remove it
            // Merge: add the value from subtree v into parent's aggregate.
            ans[find_par(u)] += ans[v] - del[v]; 
            // "Cut" the subtree v by updating BIT: subtract 1 from every node in v's Euler interval.
            BITree.update_range(g.tin[v], g.tout[v], -1);
        } else { // if edge is not active, then add it back (merge)
            ans[v] = del[v] = ans[find_par(u)];
            BITree.update_range(g.tin[v], g.tout[v], 1);
        }
        used[k] ^= 1;
    }
    
    // Process queries: for each query node, output the aggregate of its component.
    while(q--) {
        int u; 
        cin >> u; 
        u--; // convert to 0-index
        cout << ans[find_par(u)] << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
    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...