Submission #970386

#TimeUsernameProblemLanguageResultExecution timeMemory
970386maksim1744Digital Circuit (IOI22_circuit)C++17
100 / 100
698 ms35260 KiB
/* author: Maksim1744 created: 26.04.2024 15:57:25 */ #include "bits/stdc++.h" using namespace std; using ll = long long; using ld = long double; #define mp make_pair #define pb push_back #define eb emplace_back #define sum(a) ( accumulate ((a).begin(), (a).end(), 0ll)) #define mine(a) (*min_element((a).begin(), (a).end())) #define maxe(a) (*max_element((a).begin(), (a).end())) #define mini(a) ( min_element((a).begin(), (a).end()) - (a).begin()) #define maxi(a) ( max_element((a).begin(), (a).end()) - (a).begin()) #define lowb(a, x) ( lower_bound((a).begin(), (a).end(), (x)) - (a).begin()) #define uppb(a, x) ( upper_bound((a).begin(), (a).end(), (x)) - (a).begin()) template<typename T> vector<T>& operator-- (vector<T> &v){for (auto& i : v) --i; return v;} template<typename T> vector<T>& operator++ (vector<T> &v){for (auto& i : v) ++i; return v;} template<typename T> istream& operator>>(istream& is, vector<T> &v){for (auto& i : v) is >> i; return is;} template<typename T> ostream& operator<<(ostream& os, vector<T> v){for (auto& i : v) os << i << ' '; return os;} template<typename T, typename U> pair<T,U>& operator-- (pair<T, U> &p){--p.first; --p.second; return p;} template<typename T, typename U> pair<T,U>& operator++ (pair<T, U> &p){++p.first; ++p.second; return p;} template<typename T, typename U> istream& operator>>(istream& is, pair<T, U> &p){is >> p.first >> p.second; return is;} template<typename T, typename U> ostream& operator<<(ostream& os, pair<T, U> p){os << p.first << ' ' << p.second; return os;} template<typename T, typename U> pair<T,U> operator-(pair<T,U> a, pair<T,U> b){return mp(a.first-b.first, a.second-b.second);} template<typename T, typename U> pair<T,U> operator+(pair<T,U> a, pair<T,U> b){return mp(a.first+b.first, a.second+b.second);} template<typename T, typename U> void umin(T& a, U b){if (a > b) a = b;} template<typename T, typename U> void umax(T& a, U b){if (a < b) a = b;} #ifdef HOME #define SHOW_COLORS #include "/mnt/c/Libs/tools/print.cpp" #else #define show(...) void(0) #define debugf(fun) fun #define debugv(var) var #define mclock void(0) #define shows void(0) #define debug if (false) #define OSTREAM(...) ; #define OSTREAM0(...) ; #endif namespace mint_ns { template<auto P> struct Modular { using value_type = decltype(P); value_type value; Modular(long long k = 0) : value(norm(k)) {} friend Modular<P>& operator += ( Modular<P>& n, const Modular<P>& m) { n.value += m.value; if (n.value >= P) n.value -= P; return n; } friend Modular<P> operator + (const Modular<P>& n, const Modular<P>& m) { Modular<P> r = n; return r += m; } friend Modular<P>& operator -= ( Modular<P>& n, const Modular<P>& m) { n.value -= m.value; if (n.value < 0) n.value += P; return n; } friend Modular<P> operator - (const Modular<P>& n, const Modular<P>& m) { Modular<P> r = n; return r -= m; } friend Modular<P> operator - (const Modular<P>& n) { return Modular<P>(-n.value); } friend Modular<P>& operator *= ( Modular<P>& n, const Modular<P>& m) { n.value = n.value * 1ll * m.value % P; return n; } friend Modular<P> operator * (const Modular<P>& n, const Modular<P>& m) { Modular<P> r = n; return r *= m; } friend Modular<P>& operator /= ( Modular<P>& n, const Modular<P>& m) { return n *= m.inv(); } friend Modular<P> operator / (const Modular<P>& n, const Modular<P>& m) { Modular<P> r = n; return r /= m; } Modular<P>& operator ++ ( ) { return *this += 1; } Modular<P>& operator -- ( ) { return *this -= 1; } Modular<P> operator ++ (int) { Modular<P> r = *this; *this += 1; return r; } Modular<P> operator -- (int) { Modular<P> r = *this; *this -= 1; return r; } friend bool operator == (const Modular<P>& n, const Modular<P>& m) { return n.value == m.value; } friend bool operator != (const Modular<P>& n, const Modular<P>& m) { return n.value != m.value; } explicit operator int() const { return value; } explicit operator bool() const { return value; } explicit operator long long() const { return value; } constexpr static value_type mod() { return P; } value_type norm(long long k) { if (!(-P <= k && k < P)) k %= P; if (k < 0) k += P; return k; } Modular<P> inv() const { value_type a = value, b = P, x = 0, y = 1; while (a != 0) { value_type k = b / a; b -= k * a; x -= k * y; swap(a, b); swap(x, y); } return Modular<P>(x); } }; template<auto P> Modular<P> pow(Modular<P> m, long long p) { Modular<P> r(1); while (p) { if (p & 1) r *= m; m *= m; p >>= 1; } return r; } template<auto P> ostream& operator << (ostream& o, const Modular<P>& m) { return o << m.value; } template<auto P> istream& operator >> (istream& i, Modular<P>& m) { long long k; i >> k; m.value = m.norm(k); return i; } template<auto P> string to_string(const Modular<P>& m) { return to_string(m.value); } using Mint = Modular<(int)1e9 + 2022>; // using Mint = Modular<998244353>; // using Mint = long double; vector<Mint> f, fi; void init_C(int n) { f.assign(n, 1); fi.assign(n, 1); for (int i = 2; i < n; ++i) f[i] = f[i - 1] * i; fi.back() = Mint(1) / f.back(); for (int i = n - 2; i >= 0; --i) fi[i] = fi[i + 1] * (i + 1); } Mint C(int n, int k) { if (k < 0 || k > n) return 0; else return f[n] * fi[k] * fi[n - k]; } } using namespace mint_ns; namespace segtree { // This implementation is disgusting, but it seems to work and do it faster than previous version. template<typename Item> Item tree_merge(const Item& a, const Item& b) { Item i; i.update(a, b); return i; } template<typename Item, bool lazy> struct Pusher {}; template<typename Item> struct Pusher<Item, false> { void push(const vector<Item>&, int, int, int) {} Item ask_on_segment(const vector<Item>& tree, int n, int l, int r) { l |= n; r |= n; Item resl, resr; while (l <= r) { if (l & 1) { resl = tree_merge(resl, tree[l]); ++l; } if (!(r & 1)) { resr = tree_merge(tree[r], resr); --r; } l >>= 1; r >>= 1; } return tree_merge(resl, resr); } void push_point(const vector<Item>&, int, int) {} template<typename P> int lower_bound(const vector<Item>& tree, int n, int l, P p) { Item cur; if (p(cur)) return l - 1; l |= n; int r = n | (n - 1); // carefully go up while (true) { if (p(tree_merge(cur, tree[l]))) { break; } if (l == r) return n; if (l & 1) { cur = tree_merge(cur, tree[l]); ++l; } l >>= 1; r >>= 1; } // usual descent from l while (l < n) { if (p(tree_merge(cur, tree[l * 2]))) { l = l * 2; } else { cur = tree_merge(cur, tree[l * 2]); l = l * 2 + 1; } } return (l ^ n); } template<typename P> int lower_bound_rev(const vector<Item>& tree, int n, int r, P p) { Item cur; if (p(cur)) return r + 1; r |= n; int l = n; // carefully go up while (true) { if (p(tree_merge(tree[r], cur))) { break; } if (l == r) return -1; if (!(r & 1)) { cur = tree_merge(tree[r], cur); --r; } l >>= 1; r >>= 1; } // usual descent from r while (r < n) { if (p(tree_merge(tree[r * 2 + 1], cur))) { r = r * 2 + 1; } else { cur = tree_merge(tree[r * 2 + 1], cur); r = r * 2; } } return (r ^ n); } }; template<typename Item> struct Pusher<Item, true> { void push(vector<Item>& tree, int ind, int l, int r) { tree[ind].push(tree[ind * 2], tree[ind * 2 + 1], l, r); } Item ask_on_segment(vector<Item>& tree, int n, int l, int r) { int vl = 0, vr = n - 1; int i = 1; Item result; while (vl != vr) { int m = (vl + vr) / 2; if (l > m) { push(tree, i, vl, vr); i = i * 2 + 1; vl = m + 1; } else if (r <= m) { push(tree, i, vl, vr); i = i * 2; vr = m; } else { break; } } if (l == vl && r == vr) { return tree[i]; } push(tree, i, vl, vr); // left { int ind = i * 2; int L = vl, R = (vl + vr) / 2; while (l != L) { int m = (L + R) / 2; push(tree, ind, L, R); if (l <= m) { result = tree_merge(tree[ind * 2 + 1], result); ind *= 2; R = m; } else { ind = ind * 2 + 1; L = m + 1; } } result = tree_merge(tree[ind], result); } // right { int ind = i * 2 + 1; int L = (vl + vr) / 2 + 1, R = vr; while (r != R) { int m = (L + R) / 2; push(tree, ind, L, R); if (r > m) { result = tree_merge(result, tree[ind * 2]); ind = ind * 2 + 1; L = m + 1; } else { ind = ind * 2; R = m; } } result = tree_merge(result, tree[ind]); } return result; } void push_point(vector<Item>& tree, int n, int ind) { int l = 0, r = n - 1; int i = 1; while (l != r) { push(tree, i, l, r); int m = (l + r) / 2; if (ind <= m) { r = m; i *= 2; } else { l = m + 1; i = i * 2 + 1; } } } template<typename P> pair<int, Item> _lower_bound(vector<Item>& tree, int l, P p, Item cur, int i, int vl, int vr) { if (vl == vr) { if (p(tree_merge(cur, tree[i]))) { return {vl, tree[i]}; } else { return {vl + 1, tree[i]}; } } push(tree, i, vl, vr); int m = (vl + vr) / 2; if (l > m) { return _lower_bound(tree, l, p, cur, i * 2 + 1, m + 1, vr); } else if (l <= vl) { if (!p(tree_merge(cur, tree[i]))) { return {vr + 1, tree_merge(cur, tree[i])}; } if (p(tree_merge(cur, tree[i * 2]))) { return _lower_bound(tree, l, p, cur, i * 2, vl, m); } else { return _lower_bound(tree, l, p, tree_merge(cur, tree[i * 2]), i * 2 + 1, m + 1, vr); } } else { auto [ind, it] = _lower_bound(tree, l, p, cur, i * 2, vl, m); if (ind <= m) return {ind, it}; return _lower_bound(tree, l, p, it, i * 2 + 1, m + 1, vr); } } template<typename P> int lower_bound(vector<Item>& tree, int n, int l, P p) { Item cur; if (p(cur)) return l - 1; return _lower_bound(tree, l, p, cur, 1, 0, n - 1).first; } template<typename P> pair<int, Item> _lower_bound_rev(vector<Item>& tree, int r, P p, Item cur, int i, int vl, int vr) { if (vl == vr) { if (p(tree_merge(tree[i], cur))) { return {vl, tree[i]}; } else { return {vl - 1, tree[i]}; } } push(tree, i, vl, vr); int m = (vl + vr) / 2; if (r <= m) { return _lower_bound_rev(tree, r, p, cur, i * 2, vl, m); } else if (r >= vr) { if (!p(tree_merge(tree[i], cur))) { return {vl - 1, tree_merge(cur, tree[i])}; } if (p(tree_merge(tree[i * 2 + 1], cur))) { return _lower_bound_rev(tree, r, p, cur, i * 2 + 1, m + 1, vr); } else { return _lower_bound_rev(tree, r, p, tree_merge(tree[i * 2 + 1], cur), i * 2, vl, m); } } else { auto [ind, it] = _lower_bound_rev(tree, r, p, cur, i * 2 + 1, m + 1, vr); if (ind > m) return {ind, it}; return _lower_bound_rev(tree, r, p, it, i * 2, vl, m); } } template<typename P> int lower_bound_rev(vector<Item>& tree, int n, int r, P p) { Item cur; if (p(cur)) return r + 1; return _lower_bound_rev(tree, r, p, cur, 1, 0, n - 1).first; } }; template<typename Item, bool lazy = false> struct Segtree { vector<Item> tree; Pusher<Item, lazy> pusher; int n; int n0; Segtree(int n = 0) { build(n); } template<typename U> Segtree(const vector<U>& v) { build(v); } void build(int n) { this->n0 = n; while (n & (n - 1)) ++n; this->n = n; tree.assign(n * 2, {}); } template<typename U> void build(const vector<U>& v) { build(v.size()); for (int i = 0; i < v.size(); ++i) { tree[n | i].init(v[i], i); } build(); } void build() { for (int i = n - 1; i >= 1; --i) { tree[i].update(tree[i * 2], tree[i * 2 + 1]); } } void push(int ind, int l, int r) { pusher.push(tree, ind, l, r); } template<typename T> void set(int ind, const T& t) { pusher.push_point(tree, n, ind); ind |= n; tree[ind].init(t, ind ^ n); ind >>= 1; while (ind) { tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]); ind >>= 1; } } template<typename T> void update(int ind, const T& t) { pusher.push_point(tree, n, ind); ind |= n; tree[ind].update(t, ind ^ n); ind >>= 1; while (ind) { tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]); ind >>= 1; } } Item& ith(int ind) { static_assert(!lazy, "don't use this method with lazy propagation, unless you're sure you need it"); return tree[ind | n]; } const Item& root() const { return tree[1]; } Item ask(int l, int r) { l = max(l, 0); r = min(r, n - 1); if (l > r) return {}; return pusher.ask_on_segment(tree, n, l, r); } template<typename T> void modify(int l, int r, const T& t) { static_assert(lazy, "lazy must be set to true to use this function"); l = max(l, 0); r = min(r, n - 1); if (l > r) return; int vl = 0, vr = n - 1; int i = 1; while (vl != vr) { int m = (vl + vr) / 2; if (l > m) { push(i, vl, vr); i = i * 2 + 1; vl = m + 1; } else if (r <= m) { push(i, vl, vr); i = i * 2; vr = m; } else { break; } } if (l == vl && r == vr) { tree[i].modify(t, l, r); } else { push(i, vl, vr); // left { int ind = i * 2; int L = vl, R = (vl + vr) / 2; while (l != L) { int m = (L + R) / 2; push(ind, L, R); if (l <= m) { tree[ind * 2 + 1].modify(t, m + 1, R); ind *= 2; R = m; } else { ind = ind * 2 + 1; L = m + 1; } } tree[ind].modify(t, L, R); ind >>= 1; while (ind != i) { tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]); ind >>= 1; } } // right { int ind = i * 2 + 1; int L = (vl + vr) / 2 + 1, R = vr; while (r != R) { int m = (L + R) / 2; push(ind, L, R); if (r > m) { tree[ind * 2].modify(t, L, m); ind = ind * 2 + 1; L = m + 1; } else { ind = ind * 2; R = m; } } tree[ind].modify(t, L, R); ind >>= 1; while (ind != i) { tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]); ind >>= 1; } } tree[i].update(tree[i * 2], tree[i * 2 + 1]); } i >>= 1; while (i) { tree[i].update(tree[i * 2], tree[i * 2 + 1]); i >>= 1; } } // first index r such that p(tree.ask(l, r)) == true // if p() is true for empty item, return l-1 // if p() is never true, returns n template<typename P> int lower_bound(int l, P p) { l = max(l, 0); if (l >= n0) return n0; return min(n0, pusher.lower_bound(tree, n, l, p)); } // similarly to lower_bound, returns first (largest) l such that p(tree.ask(l, r)) == true template<typename P> int lower_bound_rev(int r, P p) { r = min(r, n0 - 1); if (r < 0) return -1; return pusher.lower_bound_rev(tree, n, r, p); } }; } using segtree::Segtree; struct Item { Mint sm = 0; Mint enabled_sm = 0; int mod = 0; template<typename T> void init(const T& t, int ind) { sm = t; enabled_sm = 0; mod = 0; } void update(const Item& a, const Item& b) { sm = a.sm + b.sm; enabled_sm = a.enabled_sm + b.enabled_sm; } //// similar to init, but more convenient for doing a[i] += x, implement only if needed // template<typename T> // void update(const T& t, int ind) {} // apply here, save for children template<typename T> void modify(const T& m, int l, int r) { if (!m) return; mod ^= 1; enabled_sm = sm - enabled_sm; } void push(Item& a, Item& b, int l, int r) { if (mod) { int m = (l + r) / 2; a.modify(mod, l, m); b.modify(mod, m + 1, r); mod = 0; } } }; template<class Fun> class y_combinator_result { Fun fun_; public: template<class T> explicit y_combinator_result(T &&fun): fun_(std::forward<T>(fun)) {} template<class ...Args> decltype(auto) operator()(Args &&...args) { return fun_(std::ref(*this), std::forward<Args>(args)...); } }; template<class Fun> decltype(auto) y_combinator(Fun &&fun) { return y_combinator_result<std::decay_t<Fun>>(std::forward<Fun>(fun)); } // auto gcd = std::y_combinator([](auto gcd, int a, int b) -> int { // return b == 0 ? a : gcd(b, a % b); // }); Segtree<Item, true> tree; int n; void init(int N, int m, std::vector<int> P, std::vector<int> A) { n = N; vector<vector<int>> g(n + m); for (int i = 0; i < P.size(); ++i) { if (P[i] != -1) g[P[i]].pb(i); } vector<Mint> prod(n + m, 1); y_combinator([&](auto dfs, int v) -> void { prod[v] = (v < n ? g[v].size() : 1); for (int k : g[v]) { dfs(k); prod[v] *= prod[k]; } })(0); vector<Mint> coef(m, 0); show(prod); y_combinator([&](auto dfs, int v, Mint p) -> void { if (v >= n) coef[v - n] = p; vector<Mint> pref, suf; for (int k : g[v]) { pref.pb(prod[k]); suf.pb(prod[k]); } for (int i = 1; i < pref.size(); ++i) pref[i] *= pref[i - 1]; for (int i = (int)suf.size() - 2; i >= 0; --i) suf[i] *= suf[i + 1]; for (int i = 0; i < g[v].size(); ++i) { Mint here = p; if (i) here *= pref[i - 1]; if (i + 1 < g[v].size()) here *= suf[i + 1]; dfs(g[v][i], here); } })(0, 1); show(coef); tree = Segtree<Item, true>(coef); for (int i = 0; i < m; ++i) { if (A[i]) tree.modify(i, i, 1); } } int count_ways(int l, int r) { tree.modify(l - n, r - n, 1); return (int)tree.root().enabled_sm; } #ifdef HOUSE int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int n, m, q; cin >> n >> m >> q; vector<int> p(n + m), a(m); cin >> p >> a; init(n, m, p, a); while (q--) { int l, r; cin >> l >> r; cout << count_ways(l, r) << '\n'; } return 0; } #endif

Compilation message (stderr)

circuit.cpp: In function 'void init(int, int, std::vector<int>, std::vector<int>)':
circuit.cpp:641:23: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  641 |     for (int i = 0; i < P.size(); ++i) {
      |                     ~~^~~~~~~~~~
circuit.cpp: In lambda function:
circuit.cpp:663:27: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<mint_ns::Modular<1000002022> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  663 |         for (int i = 1; i < pref.size(); ++i)
      |                         ~~^~~~~~~~~~~~~
circuit.cpp: In instantiation of 'init(int, int, std::vector<int>, std::vector<int>)::<lambda(auto:24, int, mint_ns::Mint)> [with auto:24 = std::reference_wrapper<y_combinator_result<init(int, int, std::vector<int>, std::vector<int>)::<lambda(auto:24, int, mint_ns::Mint)> > >; mint_ns::Mint = mint_ns::Modular<1000002022>]':
circuit.cpp:624:20:   required from 'decltype(auto) y_combinator_result<Fun>::operator()(Args&& ...) [with Args = {int, int}; Fun = init(int, int, std::vector<int>, std::vector<int>)::<lambda(auto:24, int, mint_ns::Mint)>]'
circuit.cpp:673:12:   required from here
circuit.cpp:663:27: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<mint_ns::Modular<1000002022> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
circuit.cpp:667:27: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  667 |         for (int i = 0; i < g[v].size(); ++i) {
      |                         ~~^~~~~~~~~~~~~
circuit.cpp:670:23: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  670 |             if (i + 1 < g[v].size()) here *= suf[i + 1];
      |                 ~~~~~~^~~~~~~~~~~~~
circuit.cpp: In instantiation of 'void segtree::Segtree<Item, lazy>::build(const std::vector<U>&) [with U = mint_ns::Modular<1000002022>; Item = Item; bool lazy = true]':
circuit.cpp:404:14:   required from 'segtree::Segtree<Item, lazy>::Segtree(const std::vector<U>&) [with U = mint_ns::Modular<1000002022>; Item = Item; bool lazy = true]'
circuit.cpp:675:36:   required from here
circuit.cpp:417:27: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<mint_ns::Modular<1000002022> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  417 |         for (int i = 0; i < v.size(); ++i) {
      |                         ~~^~~~~~~~~~
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...