제출 #391316

#제출 시각아이디문제언어결과실행 시간메모리
391316HegdahlRailway (BOI17_railway)C++17
100 / 100
886 ms30320 KiB
#include <bits/stdc++.h>
#define ar array
 
using namespace std;
 
template<class S, class F>
struct SegTreeBase {
  
  vector<S> values;
  vector<F> queued;
  int lg2, offset;
 
  static constexpr int log2i(unsigned n) { return 32-__builtin_clz(--n); }
  SegTreeBase(const vector<S> &src)
    : lg2(log2i((int)src.size())), offset(1<<log2i((int)src.size())) {
    values.reserve(2*offset);
    values.resize(offset);
    values.insert(values.end(), src.begin(), src.end());
    values.resize(2*offset);
    queued.resize(offset);
    for (int i = offset-1; i > 0; --i) recalc(i);
  }
 
  void recalc(int I) {
    assert(I > 0 && I < offset);
    values[I] = values[2*I] * values[2*I+1];
  }
 
  void push(int I) {
    assert(I > 0 && I < offset);
    values[2*I] = queued[I] * values[2*I];
    values[2*I+1] = queued[I] * values[2*I+1];
    if (2*I < offset) {
      queued[2*I] = queued[I] * queued[2*I];
      queued[2*I+1] = queued[I] * queued[2*I+1];
    }
    queued[I] = F();
  }
 
  void push_col(int I) {
    assert(I >= offset && I < 2*offset);
    for (int lvl = lg2-1; lvl >= 0; --lvl)
      push((I>>lvl)/2);
  }
 
  void push_range(int I, int J) {
    assert(I+1 >= offset && I+1 < 2*offset);
    assert(J-1 >= offset && J-1 < 2*offset);
    assert(I+1 < J);
    for (int lvl = lg2-1; lvl >= 0; --lvl) {
      push(((I+1)>>lvl)/2);
      if (I+1 != J-1) push(((J-1)>>lvl)/2);
    }
  }
 
  void set(int i, S v) {
    assert(i >= 0 && i < offset);
    i += offset;
    push_col(i);
    values[i] = v;
    while (i /= 2) recalc(i);
  }
 
  void upd_node(int I, const F &f) {
    assert(I > 0 && I < 2*offset);
    values[I] = f * values[I];
    if (I < offset) queued[I] = f * queued[I];
  }
 
  void upd(int i, const F &f) {
    assert(i >= 0 && i < offset);
    i += offset;
    push_col(i);
    upd_node(i, f);
    while (i/=2) recalc(i);
  }
 
  void upd(int i, int j, const F &f) {
    assert(i >= 0 && i < offset);
    assert(j >= 0 && j < offset);
    assert(i <= j);
    i += offset-1;
    j += offset+1;
    int oi = i, oj = j;
    push_range(i, j);
    while (i+1 < j) {
      if ((i&1)==0) upd_node(i+1, f);
      if ((j&1)==1) upd_node(j-1, f);
      i >>= 1, j >>= 1;
    }
    i = oi+1, j = oj-1;
    for (int lvl = 1; lvl <= lg2; lvl++) {
      if (__builtin_ctz(i) < lvl) recalc(i >> lvl);
      if (__builtin_ctz(j+1) < lvl) recalc(j >> lvl);
    }
  }
 
  S qry(int i) {
    assert(i >= 0 && i < offset);
    i += offset;
    push_col(i);
    return values[i];
  }
 
  S qry(int i, int j) {
    assert(i >= 0 && i < offset);
    assert(j >= 0 && j < offset);
    assert(i <= j);
    i += offset-1;
    j += offset+1;
    push_range(i, j);
    S ls, rs;
    while (i+1 < j) {
      if ((i&1)==0) ls = ls * values[i+1];
      if ((j&1)==1) rs = values[j-1] * rs;
      i >>= 1, j >>= 1;
    }
    return ls * rs;
  }
 
  template<class Cmp>
  int upper_bound(S t, Cmp cmp) {
    if (cmp(values[1], t)) return offset;
    int lvl = lg2;
    int I = 1;
    S pre;
    while (lvl--) {
      I *= 2;
      push(I/2);
      if (cmp(pre*values[I], t)) {
        pre = pre*values[I];
        ++I;
      }
    }
    return I - offset;
  }
 
};
 
struct SumS {
  int w = 1;
  int s = 0;
  SumS operator*(const SumS &rhs) const {
    return {w+rhs.w, s+rhs.s};
  }
};
 
struct SumF {
  int sum = 0;
  SumF operator*(const SumF &rhs) const {
    return {rhs.sum+sum};
  }
  SumS operator*(const SumS &rhs) const {
    return {rhs.w, rhs.s + sum * rhs.w};
  }
};
 
struct TouchS {
  bool v = false;
  TouchS operator*(const TouchS &rhs) const {
    return {bool(v | rhs.v)};
  }
};
 
struct TouchF {
  bool s0 = false;
  bool s1 = false;
  TouchF operator*(const TouchF &rhs) const {
    if (s0) return {true, false};
    if (s1) return {false, true};
    return rhs;
  }
  TouchS operator*(const TouchS &rhs) const {
    if (s0) return {false};
    if (s1) return {true};
    return rhs;
  }
};
 
using SumST = SegTreeBase<SumS, SumF>;
using TouchST = SegTreeBase<TouchS, TouchF>;
 
const int mxN = 1e5;
 
vector<ar<int, 2>> g[mxN];
 
int sz[mxN];
int up_id[mxN];
int dof[mxN];
int up[20][mxN];
 
int dfs1(int cur, int prv, int d) {
  sz[cur] = 1;
  dof[cur] = d;
  for (auto [nxt, nn] : g[cur]) {
    if (nxt == prv) continue;
    sz[cur] += dfs1(nxt, cur, d+1);
    up_id[nxt] = nn;
    up[0][nxt] = cur;
  }
  return sz[cur];
}
 
int order[mxN];
int pof[mxN];
int chain_top[mxN];
 
void dfs2(int &I, int cur, int prv, int ct) {
  int heavy = -1;
  int heavy_sz = 0;
 
  order[I] = cur;
  pof[cur] = I++;
  chain_top[cur] = ct;
 
  for (auto [nxt, nn] : g[cur]) {
    if (nxt == prv) continue;
    if (sz[nxt] <= heavy_sz) continue;
    heavy = nxt;
    heavy_sz = sz[nxt];
  }
 
  if (heavy != -1) dfs2(I, heavy, cur, ct);
  for (auto [nxt, nn] : g[cur]) {
    if (nxt == prv) continue;
    if (nxt == heavy) continue;
    dfs2(I, nxt, cur, nxt);
  }
}
 
int lca(int i, int j) {
  if (dof[i] > dof[j]) swap(i, j);
 
  for (int lvl = 19; lvl >= 0; --lvl)
    if (dof[up[lvl][j]] >= dof[i])
      j = up[lvl][j];
 
  assert(dof[i] == dof[j]);
  if (i == j) return i;
 
 
  for (int lvl = 19; lvl >= 0; --lvl)
    if (up[lvl][i] != up[lvl][j])
      i = up[lvl][i], j = up[lvl][j];
  
  assert(i != j);
  i = up[0][i], j = up[0][j];
  assert(i == j);
 
  return i;
}
 
SumST *sum_st;
TouchST *touch_st;
 
int find_hi(int i, int j) {
  //cerr << "find_hi: " << i << ' ' << j << ' ';
  //assert(lca(i, j)==j);
 
  for (int lvl = 19; lvl >= 0; --lvl) {
    if (dof[up[lvl][i]] <= dof[j]) continue;
    if (touch_st->qry(pof[up[lvl][i]]).v) continue;
    i = up[lvl][i];
  }
 
  //cerr << i << '\n';
  return up[0][i];
}
 
void add(int i, int j) {
  //assert(lca(i, j)==j);
 
  //cerr << "add " << i << ' ' << j << '\n';
 
  while (chain_top[i] != chain_top[j]) {
    sum_st->upd(pof[chain_top[i]], pof[i], {1});
    i = up[0][chain_top[i]];
  }
 
  if (i != j)
    sum_st->upd(pof[j]+1, pof[i], {1});
}
 
void touch(int i, int j) {
  //assert(lca(i, j)==j);
 
  //cerr << "touch " << i << ' ' << j << '\n';
 
  while (chain_top[i] != chain_top[j]) {
    touch_st->upd(pof[chain_top[i]], pof[i], {false, true});
    i = up[0][chain_top[i]];
  }
 
  if (i != j)
    touch_st->upd(pof[j]+1, pof[i], {false, true});
}
 
void untouch(int i, int j) {
  //assert(lca(i, j)==j);
 
  //cerr << "untouch " << i << ' ' << j << '\n';
 
  while (chain_top[i] != chain_top[j]) {
    touch_st->upd(pof[chain_top[i]], pof[i], {true, false});
    i = up[0][chain_top[i]];
  }
 
  if (i != j)
    touch_st->upd(pof[j]+1, pof[i], {true, false});
}
 
int main() {
 
  int n, m, k; cin >> n >> m >> k;
 
  for (int nn = 1; nn < n; ++nn) {
    int i, j; cin >> i >> j; --i, --j;
    //cerr << "edge: " << i << ' ' << j << '\n';
 
    g[i].push_back({j, nn});
    g[j].push_back({i, nn});
  }
 
  dfs1(0, -1, 0);
 
  for (int lvl = 0; lvl < 19; ++lvl)
    for (int i = 0; i < n; ++i)
      up[lvl+1][i] = up[lvl][up[lvl][i]];
 
  {
    int I = 0;
    dfs2(I, 0, -1, 0);
    //assert(I==n);
  }       
 
  /*
  for (int i = 0; i < n; ++i)
    cerr << chain_top[i] << " \n"[i==n-1];
  for (int i = 0; i < n; ++i)
    cerr << order[i] << " \n"[i==n-1]; // */
 
  sum_st = new SumST(vector<SumS>(n, {1, 0}));
  touch_st = new TouchST(vector<TouchS>(n, {false}));
 
  int a[mxN];
  for (int mm = 0; mm < m; ++mm) {
    int s; cin >> s;
 
    //cerr << s << ": ";
    for (int ss = 0; ss < s; ++ss) {
      cin >> a[ss], --a[ss];
      //cerr << a[ss] << ' ';
    }
 
    int hi = a[0];
    for (int ss = 1; ss < s; ++ss)
      hi = lca(hi, a[ss]);
 
    //cerr << "- " << hi << '\n';
 
    for (int ss = 0; ss < s; ++ss) {
      if (a[ss] == hi) continue;
      add(a[ss], find_hi(a[ss], hi));
      touch(a[ss], hi);
 
      /*
      cerr << "touched: ";
      for (int i = 0; i < n; ++i)
        cerr << touch_st->qry(i).v << " \n"[i==n-1]; // */
 
      /*
      cerr << "sum: ";
      for (int i = 0; i < n; ++i)
        cerr << sum_st->qry(i).s << " \n"[i==n-1]; */
    }
 
    for (int ss = 0; ss < s; ++ss) {
      if (a[ss] == hi) continue;
      untouch(a[ss], hi);
 
      /*
      cerr << "touched: ";
      for (int i = 0; i < n; ++i)
        cerr << touch_st->qry(i).v << " \n"[i==n-1]; // */
    }
 
    //cerr << '\n';
  }
 
  vector<int> ans;
  for (int i = 0; i < n; ++i)
    if (sum_st->qry(i).s >= k)
      ans.push_back(up_id[order[i]]);
  sort(ans.begin(), ans.end());
 
  cout << ans.size() << '\n';
  for (int mm : ans)
    cout << mm << ' ';
  cout << '\n';
}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...