結果

問題 No.768 Tapris and Noel play the game on Treeone
ユーザー lumc_lumc_
提出日時 2019-08-21 11:08:06
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 146 ms / 2,000 ms
コード長 7,166 bytes
コンパイル時間 1,779 ms
コンパイル使用メモリ 133,272 KB
実行使用メモリ 18,920 KB
最終ジャッジ日時 2024-04-16 23:24:50
合計ジャッジ時間 5,798 ms
ジャッジサーバーID
(参考情報)
judge4 / judge3
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
5,248 KB
testcase_01 AC 2 ms
5,376 KB
testcase_02 AC 2 ms
5,376 KB
testcase_03 AC 3 ms
5,376 KB
testcase_04 AC 3 ms
5,376 KB
testcase_05 AC 3 ms
5,376 KB
testcase_06 AC 2 ms
5,376 KB
testcase_07 AC 79 ms
12,288 KB
testcase_08 AC 34 ms
7,936 KB
testcase_09 AC 43 ms
8,832 KB
testcase_10 AC 29 ms
7,552 KB
testcase_11 AC 137 ms
17,408 KB
testcase_12 AC 136 ms
17,408 KB
testcase_13 AC 124 ms
17,024 KB
testcase_14 AC 121 ms
17,024 KB
testcase_15 AC 138 ms
17,920 KB
testcase_16 AC 137 ms
17,920 KB
testcase_17 AC 146 ms
18,176 KB
testcase_18 AC 105 ms
18,920 KB
testcase_19 AC 106 ms
17,928 KB
testcase_20 AC 95 ms
17,444 KB
testcase_21 AC 90 ms
16,432 KB
20evil_special_uni1.txt AC 128 ms
17,620 KB
20evil_special_uni2.txt AC 117 ms
16,992 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

// includes {{{
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <tuple>
#include <vector>
// #include<deque>
// #include<multiset>
// #include<bitset>
// #include<cstring>
// #include<bits/stdc++.h>
// }}}
using namespace std;
using ll = long long;

/// --- ReRooting {{{ ///

#include <cassert>
#include <functional>
#include <queue>
#include <stack>
#include <tuple>
#include <utility>
#include <vector>
template < class Monoid >
struct ReRooting {
  using size_type = std::size_t;
  using edge_type = std::tuple< size_type, size_type, size_type >;
  using graph_type = std::vector< std::vector< edge_type > >;
  using T = typename Monoid::T;
  using dig_f_type =
      std::function< T(T, size_type edge_id, size_type from, size_type to) >;
  using after_f_type =
      std::function< T(T, size_type vertex_id, size_type degree_of_this) >;
  using vector_bool_type = std::vector< int >;
  graph_type graph;

  size_type n;

  std::vector< size_type > start;
  std::vector< T > dp;
  vector_bool_type did;
  std::vector< T > L;
  std::vector< T > R;

  dig_f_type dig;
  after_f_type after;
  static T default_dig(const T &a, ...) { return a; }
  static T default_after(const T &a, ...) { return a; }

  bool built;

  ReRooting() : n(0) {}
  ReRooting(size_type n, dig_f_type dig = default_dig, after_f_type after = default_after)
      : dig(dig), after(after) {
    clear(n);
  }
  ReRooting(std::vector< std::vector< int > > graph, dig_f_type dig = default_dig,
            after_f_type after = default_after)
      : ReRooting(graph.size(), dig, after) {
    for(size_type from = 0; from < n; from++) {
      for(auto to : graph[from])
        if(static_cast< size_type >(to) < from) {
          add_edge(from, to);
        }
    }
  }

  void clear() { clear(n); }

  void clear(size_type n) {
    this->n = n;
    graph.resize(n);
    graph.assign(n, std::vector< edge_type >());
    dp.resize(3 * n);
    did.resize(3 * n);
    did.assign(3 * n, 0);
    L.resize(3 * n);
    R.resize(3 * n);
    start.resize(n);
    added = 0;
    built = 0;
  }

  size_type added = 0;
  void add_edge(size_type a, size_type b, size_type id = static_cast< size_type >(-1)) {
    assert(!built);
    assert(a < n && b < n && a != b);
    if(id == static_cast< size_type >(-1)) id = added;
    graph[a].emplace_back(b, graph[b].size(), id);
    graph[b].emplace_back(a, graph[a].size() - 1, id);
    added++;
  }

  void set_dig(dig_f_type dig = default_dig) {
    assert(!built);
    this->dig = dig;
  }

  void set_after(after_f_type after = default_after) {
    assert(!built);
    this->after = after;
  }

  void build() {
    assert(!built);
    built = 1;
    if(n == 0) return;

    assert(added == n - 1);
    for(size_type i = 0; i + 1 < n; i++) {
      start[i + 1] = start[i] + graph[i].size() + 1;
    }
    dfs_first(0, graph[0].size());
  }

public:
  T dfs(size_type i) { return dfs(i, graph[i].size()); }

  T dfs_from(size_type i, size_type j) {
    assert(built);
    assert(j < n);
    // TODO : どうする?
    // return dfs(i, , 0);
  }

private:
  T proceed_root(size_type i) {
    for(size_type x = 0; x < graph[i].size(); x++) {
      auto to = graph[i][x];
      size_type j, rev, edge_id;
      std::tie(j, rev, edge_id) = to;
      R[start[i] + x] = L[start[i] + x] = dig(dp[start[j] + rev], edge_id, i, j);
    }
    for(int x = 1; x < static_cast< int >(graph[i].size()); x++)
      L[start[i] + x] = Monoid::op(L[start[i] + x - 1], L[start[i] + x]);
    for(int x = static_cast< int >(graph[i].size()) - 2; x >= 0; x--)
      R[start[i] + x] = Monoid::op(R[start[i] + x], R[start[i] + x + 1]);
    return L[start[i] + graph[i].size() - 1];
  }

  void dfs_first(size_type i0, size_type p0) {
    std::vector< std::tuple< size_type, size_type, bool > > stk;
    stk.reserve(n);
    stk.emplace_back(i0, p0, 0);
    while(stk.size()) {
      size_type i, p;
      bool up;
      std::tie(i, p, up) = stk.back();
      stk.pop_back();
      int deg = graph[i].size() - (p != graph[i].size() ? 1 : 0);
      if(up) {
        did[start[i] + p] = 1;
        T res = Monoid::identity();
        if(p == graph[i].size()) {
          // O(deg)
          res = proceed_root(i);
        } else {
          // O(deg)
          for(size_type x = 0; x < graph[i].size(); x++)
            if(x != p) {
              size_type j, rev, edge_id;
              std::tie(j, rev, edge_id) = graph[i][x];
              res = Monoid::op(res, dig(dp[start[j] + rev], edge_id, i, j));
            }
        }
        dp[start[i] + p] = after(res, i, deg);
      } else {
        stk.emplace_back(i, p, 1);
        for(size_type x = 0; x < graph[i].size(); x++)
          if(x != p) {
            size_type j, rev, edge_id;
            std::tie(j, rev, edge_id) = graph[i][x];
            stk.emplace_back(j, rev, 0);
          }
      }
    }
  }

  T dfs(size_type i0, size_type p0) {
    assert(built);
    assert(i0 < n);
    assert(p0 <= graph[i0].size());
    if(did[start[i0] + p0]) return dp[start[i0] + p0];

    std::vector< std::tuple< size_type, size_type, bool > > stk;
    stk.reserve(n);
    stk.emplace_back(i0, p0, 0);
    while(stk.size()) {
      size_type i, p;
      bool up;
      std::tie(i, p, up) = stk.back();
      stk.pop_back();
      if(up) {
        int deg = graph[i].size() - (p != graph[i].size() ? 1 : 0);
        did[start[i] + p] = 1;
        T res = Monoid::identity();
        if(p == graph[i].size()) {
          // O(deg)
          res = proceed_root(i);
        } else {
          // O(1)
          res = Monoid::op(
              p >= 1 ? L[start[i] + p - 1] : Monoid::identity(),
              p + 1 < graph[i].size() ? R[start[i] + p + 1] : Monoid::identity());
        }
        dp[start[i] + p] = after(res, i, deg);
      } else {
        stk.emplace_back(i, p, 1);
        if(p == graph[i].size()) {
          for(size_type x = 0; x < graph[i].size(); x++) {
            size_type j, rev, edge_id;
            std::tie(j, rev, edge_id) = graph[i][x];
            if(!did[start[j] + rev]) stk.emplace_back(j, rev, 0);
          }
        } else {
          if(!did[start[i] + graph[i].size()]) {
            stk.emplace_back(i, graph[i].size(), 0);
          }
        }
      }
    }
    return dp[start[i0] + p0];
  }
};

/// }}}--- ////

// my monoid, m-act {{{
struct MyMonoid {
  using T = int;
  static T op(const T &a, const T &b) { return a && b; }
  static T identity() { return 1; }
};
// }}}

using rerooting = ReRooting< MyMonoid >;

using T = rerooting::T;

T dig(T a, int id, int from, int to) { return !a; }

T after(T a, int i, int deg) { return a; }

int n;
int main() {
  std::ios::sync_with_stdio(false), std::cin.tie(0);
  cin >> n;
  rerooting rr(n, dig, after);
  for(int i = 0; i < n - 1; i++) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    rr.add_edge(a, b);
  }
  rr.build();
  vector< int > v;
  for(int i = 0; i < n; i++)
    if(rr.dfs(i)) v.emplace_back(i);
  cout << v.size() << "\n";
  for(int e : v) cout << e + 1 << "\n";
  return 0;
}
0