제출 #1358129

#제출 시각아이디문제언어결과실행 시간메모리
1358129avighnaTourism (JOI23_tourism)C++20
28 / 100
5094 ms23276 KiB
#include <bits/stdc++.h>

using namespace std;

template <typename Fn>
class segment_tree {
  int n;
  vector<int> seg;

  Fn merge;
  int idt;

public:
  segment_tree(int n, const Fn &merge, int idt) : merge(merge), idt(idt), n(n), seg(2 * n, idt) {}

  void set(int i, int x) {
    for (seg[i += n] = x, i >>= 1; i > 0; i >>= 1) {
      seg[i] = merge(seg[2 * i], seg[2 * i + 1]);
    }
  }

  int query(int l, int r) {
    int ans = idt;
    for (l += n, r += n + 1; l < r; l >>= 1, r >>= 1) {
      if (l & 1) ans = merge(ans, seg[l++]);
      if (r & 1) ans = merge(ans, seg[--r]);
    }
    return ans;
  }
};

const int inf = 1e9;

struct query {
  int l, r, i;
};

struct node {
  int mn, cnt;
  node(int mn, int cnt) : mn(mn), cnt(cnt) {}
  node() : mn(inf), cnt(0) {}
  node operator+(const node &r) {
    if (mn < r.mn) { return *this; }
    if (r.mn < mn) { return r; }
    return {mn, cnt + r.cnt};
  }
};

class lazy_segment_tree {
  int n;
  vector<node> seg;
  vector<int> lazy;

  void push(int v) {
    seg[v].mn += lazy[v];
    lazy[2 * v] += lazy[v];
    lazy[2 * v + 1] += lazy[v];
    lazy[v] = 0;
  }

  void pull(int v) { seg[v] = seg[2 * v] + seg[2 * v + 1]; }

  void add(int v, int tl, int tr, int l, int r, int del) {
    push(v);
    if (tr < l || r < tl) { return; }
    if (l <= tl && tr <= r) {
      lazy[v] += del;
      push(v);
      return;
    }
    int tm = (tl + tr) / 2;
    add(2 * v, tl, tm, l, r, del);
    add(2 * v + 1, tm + 1, tr, l, r, del);
    pull(v);
  }

  node query(int v, int tl, int tr, int l, int r) {
    push(v);
    if (tr < l || r < tl) { return node{}; }
    if (l <= tl && tr <= r) { return seg[v]; }
    int tm = (tl + tr) / 2;
    return query(2 * v, tl, tm, l, r) + query(2 * v + 1, tm + 1, tr, l, r);
  }

  void build(int v, int tl, int tr) {
    if (tl == tr) {
      seg[v] = node{0, 1};
      return;
    }
    int tm = (tl + tr) / 2;
    build(2 * v, tl, tm);
    build(2 * v + 1, tm + 1, tr);
    pull(v);
  }

public:
  lazy_segment_tree(int n) : n(n), seg(4 * n), lazy(8 * n) { build(1, 0, n - 1); }

  void add(int l, int r, int del) { add(1, 0, n - 1, l, r, del); }
  node query(int l, int r) { return query(1, 0, n - 1, l, r); }
};

int main() {
  cin.tie(nullptr)->sync_with_stdio(false);

  int n, m, q;
  cin >> n >> m >> q;
  vector<vector<int>> adj(n + 1);
  for (int i = 0, u, v; i < n - 1; ++i) {
    cin >> u >> v;
    adj[u].push_back(v), adj[v].push_back(u);
  }
  vector<int> c(m);
  for (int &i : c) {
    cin >> i;
  }

  vector<int> sz(n + 1);
  auto dfs_sz = [&](auto &&self, int u, int p) -> void {
    if (adj[u].size() > 1 && adj[u][0] == p) { swap(adj[u][0], adj[u][1]); }
    sz[u] = 1;
    for (int &i : adj[u]) {
      if (i == p) { continue; }
      self(self, i, u);
      sz[u] += sz[i];
      if (sz[i] > sz[adj[u][0]]) { swap(i, adj[u][0]); }
    }
  };
  dfs_sz(dfs_sz, 1, 0);
  vector<int> up(n + 1);
  auto dfs_hld = [&](auto &&self, int u, int p) -> void {
    for (int &i : adj[u]) {
      if (i == p) { continue; }
      up[i] = i == adj[u][0] ? up[u] : i;
      self(self, i, u);
    }
  };
  up[1] = 1;
  dfs_hld(dfs_hld, 1, 0);

  const int w = 17;
  vector<array<int, w>> lift(n + 1);
  vector<int> dep(n + 1), tin(n + 1);
  int timer = 0;
  auto dfs = [&](auto &&self, int u, int p, int d) -> void {
    tin[u] = timer++;
    dep[u] = d;
    for (int &i : adj[u]) {
      if (i == p) { continue; }
      lift[i][0] = u;
      self(self, i, u, d + 1);
    }
  };
  lift[1][0] = 1;
  dfs(dfs, 1, 0, 0);
  for (int bt = 1; bt < w; ++bt) {
    for (int i = 1; i <= n; ++i) {
      lift[i][bt] = lift[lift[i][bt - 1]][bt - 1];
    }
  }

  auto lca = [&](int u, int v) {
    if (u == 0) { return v; }
    if (v == 0) { return u; }
    if (dep[u] < dep[v]) { // u is deeper
      swap(u, v);
    }
    int k = dep[u] - dep[v];
    for (int bt = 0; bt < w; ++bt) {
      if (k & 1 << bt) { u = lift[u][bt]; }
    }
    if (u == v) { return u; }
    for (int bt = w - 1; bt >= 0; --bt) {
      if (lift[u][bt] != lift[v][bt]) {
        u = lift[u][bt], v = lift[v][bt];
      }
    }
    return lift[u][0];
  };

  segment_tree st_lca(m, lca, 0);
  for (int i = 0; i < m; ++i) {
    st_lca.set(i, c[i]);
  }

  vector<query> queries(q);
  for (int i = 0, l, r; i < q; ++i) {
    cin >> l >> r;
    queries[i] = {l - 1, r, i};
  }

  auto get_chains_hld = [&](int u, int v) {
    vector<pair<int, int>> ans;
    while (u != v) {
      if (dep[u] < dep[v]) { swap(u, v); }
      if (up[u] == up[v]) {
        ans.push_back({tin[v], tin[u]});
        return ans;
      }
      ans.push_back({tin[up[u]], tin[u]});
      u = lift[up[u]][0];
    }
    ans.push_back({tin[u], tin[u]});
    return ans;
  };

  lazy_segment_tree st(n);
  auto apply_node = [&](int u, int del) {
    auto chains = get_chains_hld(1, u);
    for (auto &[l, r] : chains) {
      st.add(l, r, del);
    }
  };

  int L = 0, R = 0; // [L, R)
  auto add_front = [&]() {
    apply_node(c[R], 1);
    R++;
  };
  auto rem_front = [&]() {
    R--;
    apply_node(c[R], -1);
  };
  auto add_back = [&]() {
    L--;
    apply_node(c[L], 1);
  };
  auto rem_back = [&]() {
    apply_node(c[L], -1);
    L++;
  };

  vector<int> ans(q);
  for (auto &[l, r, i] : queries) {
    // L, R is where we are
    // l, r is where we need to be
    while (R < r) add_front();
    while (R > r) rem_front();
    while (L > l) add_back();
    while (L < l) rem_back();

    int lc = st_lca.query(l, r - 1);
    bool is_root = lc == 1;
    if (!is_root) { lc = lift[lc][0]; }
    if (!is_root) { apply_node(lc, -(r - l)); }
    node qval = st.query(0, n - 1);
    int zeroes = qval.mn == 0 ? qval.cnt : 0;
    if (!is_root) { apply_node(lc, r - l); }

    ans[i] = n - zeroes;
  }

  for (int &i : ans) {
    cout << i << '\n';
  }
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…