Submission #1137937

#TimeUsernameProblemLanguageResultExecution timeMemory
1137937joelgun14Spring cleaning (CEOI20_cleaning)C++20
100 / 100
147 ms26248 KiB
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#define endl "\n"
#define ll long long
#define mp make_pair
#define ins insert
#define lb lower_bound
#define pb push_back
#define ub upper_bound
#define lll __int128
#define fi first
#define se second
using namespace std;
using namespace __gnu_pbds;
typedef tree<int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_multiset;
typedef tree<int, null_type, less<int>, rb_tree_tag,tree_order_statistics_node_update> ordered_set;
const int lim2 = 1 << 17;
struct segment_tree {
  // maintains count of 1
  int a[lim2 << 1];
  bool lazy[lim2 << 1];
  segment_tree() {
    memset(a, 0, sizeof(a));
    memset(lazy, 0, sizeof(lazy));
  }
  void prop(int nd, int cl, int cr) {
    if(cl != cr) {
      lazy[nd << 1] ^= lazy[nd];
      lazy[(nd << 1) | 1] ^= lazy[nd];
    }
    if(lazy[nd] & 1)
      a[nd] = (cr - cl + 1) - a[nd];
    lazy[nd] = 0;
  }
  void update(int nd, int cl, int cr, int l, int r) {
    // flip entire range
    prop(nd, cl, cr);
    if(cl >= l && cr <= r) {
      lazy[nd] ^= 1;
      prop(nd, cl, cr);
      // cerr << "UPDATE " << cl << " " << cr << " " << a[nd] << endl;
    }
    else if(cl > r || cr < l)
      return;
    else {
      int mid = (cl + cr) >> 1;
      update(nd << 1, cl, mid, l, r);
      update((nd << 1) | 1, mid + 1, cr, l, r);
      a[nd] = a[nd << 1] + a[(nd << 1) | 1];
    }
  }
  int query(int nd, int cl, int cr, int l, int r) {
    prop(nd, cl, cr);
    if(cl >= l && cr <= r) {
      // cerr << "QUERY " << cl << " " << cr << " " << a[nd] << endl;
      return a[nd];
    }
    else if(cl > r || cr < l)
      return 0;
    else {
      int mid = (cl + cr) >> 1;
      return query(nd << 1, cl, mid, l, r) + query((nd << 1) | 1, mid + 1, cr, l, r);
    }
  }
} seg;
const int lim = 1e5 + 5;
bool vis[lim];
vector<int> edges[lim], child[lim];
int depth[lim], subtree[lim], root[lim], par[lim], in[lim], out[lim], t;
void get_subtree(int nd) {
  vis[nd] = 1;
  subtree[nd] = 1;
  for(auto i : edges[nd]) {
    if(!vis[i]) {
      par[i] = nd;
      depth[i] = depth[nd] + 1;
      get_subtree(i);
      child[nd].pb(i);
      subtree[nd] += subtree[i];
      if(subtree[child[nd].back()] > subtree[child[nd][0]])
        swap(child[nd].back(), child[nd][0]);
    }
  }
}
void dfs_hld(int nd) {
  in[nd] = ++t;
  for(auto i : child[nd]) {
    root[i] = child[nd][0] == i ? root[nd] : i;
    dfs_hld(i);
  }
  out[nd] = t;
}
void update(int u) {
  // update to root, change parity of everything
  while(u != 0) {
    // DON'T UPDATE ROOT
    seg.update(1, 0, lim2 - 1, max(2, in[root[u]]), in[root[u]] + depth[u] - depth[root[u]]);
    u = par[root[u]];
  }
}
int dfs(int nd, bool first = 0) {
  int sum_c = 0;
  for(auto x : child[nd]) {
    sum_c += dfs(x, 0);
  }
  // cerr << nd << " " << sum_c << endl;
  // for leaf, set to 1
  sum_c = max(sum_c, 1);
  // if even, to par get +1 extra
  if(!first && (sum_c & 1) == 0)
    seg.update(1, 0, lim2 - 1, in[nd], in[nd]);
  return sum_c;
}
int main() {
  ios_base::sync_with_stdio(0); cin.tie(NULL);
  int n, q;
  cin >> n >> q;
  int deg[n + 5];
  memset(deg, 0, sizeof(deg));
  for(int i = 1; i < n; ++i) {
    int u, v;
    cin >> u >> v;
    edges[u].pb(v);
    edges[v].pb(u);
    ++deg[u], ++deg[v];
  }
  int leaf = 0;
  int r = 1;
  for(int i = 1; i <= n; ++i) {
    if(deg[i] == 1)
      ++leaf;
    else {
      if(deg[i] > deg[r])
        r = i;
    }
  }
  // cerr << "DEB " << r << " " << deg[r] << endl;
  get_subtree(r);
  root[r] = r;
  dfs_hld(r);
  dfs(r, 1);
  // even -> +1
  // odd -> 0
  // star case WA
  // perfect binary tree AC
  // all off by 1? (too much)
  // small degree correct, large degree incorrect, what is the issue?
  // degree 1/2 correct
  // star incorrect
  while(q--) {
    int d;
    cin >> d;
    vector<int> v(d);
    for(int i = 0; i < d; ++i)
      cin >> v[i];
    for(auto x : v) {
      if(deg[x] == 1)
        --leaf;
      else
        update(x);
      ++deg[x];
    }
    // cerr << leaf << " " << d << endl;
    // n + d - 1 -> number of edges
    // seg.query -> number of double crossed edges
    if((leaf + d) & 1)
      cout << -1 << endl;
    else
      cout << seg.query(1, 0, lim2 - 1, 0, lim2 - 1) + n - 1 + d << endl;
    for(auto x : v) {
      --deg[x];
      if(deg[x] == 1)
        ++leaf;
      else
        update(x);
    }
    // cerr << "SEP" << endl;
  }
  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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...