Submission #629358

#TimeUsernameProblemLanguageResultExecution timeMemory
629358dacin21Digital Circuit (IOI22_circuit)C++17
100 / 100
1077 ms14140 KiB
#include "circuit.h"

#include <bits/stdc++.h>
using namespace std;

template<typename traits>
class Mod_Int{
public:
    using int_t = typename traits::int_t;
    using long_t = typename traits::long_t;
    static constexpr int_t mod(){ return traits::get_mod(); };

    struct Summer{
    public:
        static constexpr long_t modmod(){ return traits::get_mod()*(long_t)traits::get_mod(); };
        static long_t modmod_step(long_t const& val){
            return val >= modmod() ? val-modmod() : val;
        }

        Summer() : val{} {}
        explicit Summer(Mod_Int const&o) : val(o.get_value()){}
        operator Mod_Int() const {
            return Mod_Int(mod_full(val));
        }

        Summer operator-(Summer const&o){
            return Summer(modmod() - modmod_step(o.val));
        }
        Summer& operator+=(Summer const&o){
            val = modmod_step(val+o.val);
            return *this;
        }
        Summer& operator-=(Summer const&o){
            return operator-=(-o);
        }
        Summer& addmul(Mod_Int const&a, Mod_Int const&b){
            val = modmod_step(val + a.get_value()*(long_t)b.get_value());
            return *this;
        }

    private:
        long_t val;
    };


    Mod_Int() : value(0) {}
    Mod_Int(int_t value_) : value(value_) {}

    friend ostream& operator<<(ostream&o, Mod_Int const&val){
        return o << val.value;
    }
    friend istream& operator>>(istream&i, Mod_Int &val){
         i >> val.value;
         val.value = mod_full(val.value);
         return i;
    }
    int_t const& get_value() const {
        return value;
    }

    Mod_Int operator+(Mod_Int const&o) const {
        Mod_Int ret(mod_step(value + o.value));
        return ret;
    }
    Mod_Int& operator+=(Mod_Int const&o){
        return *this = *this + o;
    }
    Mod_Int& operator++(){
        return operator+=(int_t{1});
    }
    Mod_Int operator-() const{
        Mod_Int ret(mod_step(mod() - value));
        return ret;
    }
    Mod_Int operator-(Mod_Int const&o) const {
        return operator+(-o);
    }
    Mod_Int& operator-=(Mod_Int const&o){
        return operator+=(-o);
    }
    Mod_Int& operator--(){
        return operator-=(int_t{1});
    }
    friend Mod_Int operator*(Mod_Int const&a, Mod_Int const&b) {
        Mod_Int ret(mod_full(a.value * static_cast<long_t>(b.value)));
        return ret;
    }
    Mod_Int& operator*=(Mod_Int const&o){
        return *this = *this * o;
    }
    Mod_Int inv() const {
        return inv_impl(value);
    }
    Mod_Int operator/(Mod_Int const&o) const {
        return *this * o.inv();
    }
    Mod_Int& operator/=(Mod_Int const&o) {
        return *this = *this / o;
    }

    bool operator==(Mod_Int const&o) const {
        return value == o.value;
    }
    bool operator!=(Mod_Int const&o) const {
        return !(*this == o);
    }
    bool operator!() const {
        return !value;
    }

private:
    static int_t mod_step(int_t const& val){
        return val >= mod() ? val-mod() : val;
    }
    static int_t mod_full(long_t const&val){
        return mod() ? val%mod() : val;
    }
    static Mod_Int inv_impl(Mod_Int const& val){
        if(mod() == 0){
            assert(val*val == 1);
            return val;
        }
        int_t value = val.value;
        constexpr size_t cache_size = traits::inv_cache_size()+1;
        static_assert(cache_size > 1);
        static array<Mod_Int, cache_size> cache = [](){
            array<Mod_Int, cache_size> ret;
            ret[1] = 1;
            for(int_t i=2;i<cache_size && i < mod();++i){
                ret[i] = -ret[mod()%i] * (mod()/i);
            }
            return ret;
        } ();
        assert(value != 0);
        Mod_Int factor = 1;
        while(value >= cache_size){
            factor *= - Mod_Int(mod() / value);
            value = mod() % value;
        }
        assert(value != 0);
        assert(factor != 0  && value != 0);
        return factor * cache[value];
    }

    int_t value;
};

template<uint32_t mod>
struct fixed_mod{
    using int_t = uint32_t;
    using long_t = uint64_t;
    static_assert(mod != 0, "Negative numbers won't work.");
    static_assert(numeric_limits<int_t>::max()/2 >= mod, "Addition might overflow.");
    static constexpr size_t inv_cache_size(){ return 30000; }
    static constexpr int_t get_mod(){ return mod; }
};
#ifdef __SIZEOF_INT128__
template<uint64_t mod>
struct fixed_mod_long{
    using int_t = uint64_t;
    using long_t = __int128;
    static_assert(mod != 0, "Negative numbers won't work.");
    static_assert(numeric_limits<int_t>::max()/2 >= mod, "Addition might overflow.");
    static constexpr size_t inv_cache_size(){ return 30000; }
    static constexpr int_t get_mod(){ return mod; }
};
#endif // __SIZEOF_INT128__
struct no_mod{
    using int_t  = int64_t;
    using long_t = int_t;
    static constexpr size_t inv_cache_size(){ return 1; }
    static constexpr int_t get_mod(){ return 0; }
};
struct mutable_mod{
    using int_t = uint32_t;
    using long_t = uint64_t;
    static int_t mod;
    // can't use cache if mod is changing
    static constexpr size_t inv_cache_size(){ return 1; }
    static int_t get_mod(){ return mod; }
};
mutable_mod::int_t mutable_mod::mod = 1000000007;

using num = Mod_Int<fixed_mod<1'000'002'022> >;

//really fast iterative segment-tree implementation
template<class Segtree_Data>
struct Segtree{
	int N, height;
	vector<typename Segtree_Data::node_t> data;
	vector<typename Segtree_Data::update_t> lazy;
	Segtree(vector<typename Segtree_Data::node_t> const&base):N(base.size()), height(__builtin_clz(1)-__builtin_clz(N)), data(2*N, Segtree_Data::node_ne()), lazy(2*N, Segtree_Data::update_ne()){
		copy(base.begin(), base.end(), data.begin()+N);
		for(int i=N-1;i>=0;--i)
			data[i]=Segtree_Data::merge_nodes(data[i<<1], data[i<<1|1]);
	}
	Segtree(int n):N(n), height(__builtin_clz(1)-__builtin_clz(N)), data(2*N, Segtree_Data::node_ne()), lazy(2*N, Segtree_Data::update_ne()){
		for(int i=N-1;i>=0;--i)
			data[i]=Segtree_Data::merge_nodes(data[i<<1], data[i<<1|1]);
	}
	void local_update(int pos, typename Segtree_Data::update_t const&val){
		Segtree_Data::update_node(data[pos], val);
		if(pos<N) lazy[pos] = Segtree_Data::merge_lazy(lazy[pos], val);
	}
	void push(int pos){
		for(int s=height;s>0;--s){
			int i=pos>>s;
			if(lazy[i]!=Segtree_Data::update_ne()){
				local_update(i<<1, lazy[i]);
				local_update(i<<1|1, lazy[i]);
				lazy[i]=Segtree_Data::update_ne();
			}
		}
	}
	void re_path(int pos){
		while(pos>>=1) Segtree_Data::update_node(data[pos] = Segtree_Data::merge_nodes(data[pos<<1], data[pos<<1|1]), lazy[pos]);
	}
	void update(int l, int r, typename Segtree_Data::update_t const&val){
		int l2=l+=N, r2=r+=N;
		push(l2); push(r2-1);
		for(;l<r;l>>=1, r>>=1){
			if(l&1) local_update(l++, val);
			if(r&1) local_update(--r, val);
		}
		re_path(l2);re_path(r2-1);
	}
	typename Segtree_Data::node_t query(int l, int r){
		push(l+N); push(r+N-1);
		typename Segtree_Data::node_t retL=Segtree_Data::node_ne(), retR=Segtree_Data::node_ne();
		for(l+=N, r+=N;l<r;l>>=1, r>>=1){
			if(l&1)retL=Segtree_Data::merge_nodes(retL, data[l++]);
			if(r&1)retR=Segtree_Data::merge_nodes(data[--r], retR);
		}
		return Segtree_Data::merge_nodes(retL, retR);
	}
};
struct Node{
    num on, off;
};
struct Segtreedata{
    typedef Node node_t;
    typedef int update_t;
    static node_t node_ne() {return Node{0, 0};}
    static update_t update_ne(){return 0;}
    static node_t merge_nodes(node_t const&left, node_t const&right){
        return Node{left.on+right.on, left.off+right.off};
    }
    static void update_node(node_t &node, update_t const&update){
        if(update % 2){
            swap(node.on, node.off);
        }
    }
    static update_t merge_lazy(update_t const&old, update_t const&update){
        return old + update;
    }
};

Segtree<Segtreedata> st(0);
int NN, MM;

void init(int N, int M, vector<int> p, vector<int> a) {
    MM = M; NN=N;
    // [0, N) is computed, [N, N+M) is given
    vector<vector<int> > ch(N);
    for(int i=1; i<N+M; ++i) ch[p[i]].push_back(i);
    vector<num> states(N+M, num(1));
    vector<num> down(N+M, num(1));
    vector<num> pre, suff;
    for(int i=N-1; i>=0; --i){
        auto &e = ch[i];
        const int d = ch[i].size();
        pre.assign(d+1, num(1));
        suff.assign(d+1, num(1));
        for(int j=0; j<d; ++j){
            pre[j+1] = pre[j] * states[e[j]];
        }
        for(int j = d-1; j>=0; --j){
            suff[j] = suff[j+1] * states[e[j]];
        }
        for(int j=0; j<d; ++j){
            down[e[j]] = pre[j] * suff[j+1];
        }
        states[i] = pre.back() * num(d);
    }
    for(int i=1; i<N+M; ++i){
        down[i] *= down[p[i]];
    }
    /*for(int i=N; i<N+M; ++i){
        cerr << down[i] << " ";
    }
    cerr << "\n";*/

    vector<Node> base(M);
    for(int i=0; i<M; ++i){
        base[i] = a[i] ? Node{down[N+i], 0} : Node{0, down[N+i]};
        // base[i] = Node{down[N+i], 0};
    }
    st = decltype(st)(base);
}

int count_ways(int L, int R) {
  L -= NN;
  R -= NN;
  ++R;
  st.update(L, R, 1);
  const num ans = st.query(0, MM).on;
  return ans.get_value();
}
#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...