Submission #1105500

#TimeUsernameProblemLanguageResultExecution timeMemory
1105500Zero_OPDigital Circuit (IOI22_circuit)C++17
100 / 100
1008 ms39884 KiB
#include <bits/stdc++.h>

#ifndef LOCAL
    #include "circuit.h"
#endif // LOCAL

using namespace std;

#define rep(i, l, r) for(int i = (l), _r = (r); i < _r; ++i)
#define FOR(i, l, r) for(int i = (l), _r = (r); i <= _r; ++i)
#define ROF(i, r, l) for(int i = (r), _l = (l); i >= _l; --i)
#define all(v) begin(v), end(v)
#define compact(v) v.erase(unique(all(v)), end(v))
#define sz(v) (int)v.size()
#define dbg(x) "[" #x " = " << (x) << "]"
#define file(name) if(fopen(name".inp", "r")) freopen(name".inp", "r", stdin), freopen(name".out", "w", stdout);

template<typename T>
bool minimize(T& a, const T& b){
    if(a > b) return a = b, true; return false;
}

template<typename T>
bool maximize(T& a, const T& b){
    if(a < b) return a = b, true; return false;
}

using ll = long long;
using ld = long double;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
template<typename T> T random_int(T l, T r){ return uniform_int_distribution<T>(l, r)(rng); }
template<typename T> T random_real(T l, T r){ return uniform_real_distribution<T>(l, r)(rng); }

const int MAX = 2e5 + 5;
const int mod = 1e9 + 2022;

int n, m;
vector<int> adj[MAX];
bool state[MAX];

int dp[MAX][2], total_ways[MAX], eval[MAX];

int add(int a, int b){
    return a + b < mod ? a + b : a + b - mod;
}

int multiply(int a, int b){
    return 1LL * a * b % mod;
}

int subtract(int a, int b){
    return a < b ? a - b + mod : a - b;
}

bool isLeaf(int u){
    return n <= u;
}

struct node{
    int total, one;
    node(int total = 0, int one = 0) : total(total), one(one) {}
    void flip(){ one = subtract(total, one); }
    friend node operator + (const node& a, const node& b){
        return node(add(a.total, b.total), add(a.one, b.one));
    }
};

namespace SegmentTree{
    node st[MAX << 1];
    int lazy[MAX << 1];

    void build(int id, int l, int r){
        if(l == r){
            st[id] = node(eval[l], (int)state[l] * eval[l]);
        } else{
            int mid = l + r >> 1;
            build(id << 1, l, mid);
            build(id << 1 | 1, mid + 1, r);
            st[id] = st[id << 1] + st[id << 1 | 1];
        }
    }

    void apply(int id){
        st[id].flip();
        lazy[id] ^= 1;
    }

    void lazyDown(int id){
        if(lazy[id]){
            apply(id << 1);
            apply(id << 1 | 1);
            lazy[id] = 0;
        }
    }

    void update(int id, int l, int r, int u, int v){
        if(u <= l && r <= v) apply(id);
        else{
            int mid = l + r >> 1;
            lazyDown(id);
            if(u <= mid) update(id << 1, l, mid, u, v);
            if(mid < v) update(id << 1 | 1, mid + 1, r, u, v);
            st[id] = st[id << 1] + st[id << 1 | 1];
        }
    }

    int get(){
        return st[1].one;
    }
}

void predfs(int u){
    if(isLeaf(u)){
        total_ways[u] = 1;
        return;
    }

    total_ways[u] = sz(adj[u]);
    for(int v : adj[u]){
        predfs(v);
        total_ways[u] = multiply(total_ways[u], total_ways[v]);
    }
}

void dfs(int u, int mult){
    if(isLeaf(u)){
        eval[u - n] = mult;
        return;
    }

    int k = sz(adj[u]);
    vector<int> pref(k), suff(k);
    for(int i = 0; i < k; ++i){
        pref[i] = suff[i] = total_ways[adj[u][i]];
    }

    for(int i = 1; i < k; ++i){
        pref[i] = multiply(pref[i - 1], pref[i]);
    }

    for(int i = k - 2; i >= 0; --i){
        suff[i] = multiply(suff[i], suff[i + 1]);
    }

    for(int i = 0; i < k; ++i){
        int cur = multiply(i > 0 ? pref[i - 1] : 1, i + 1 < k ? suff[i + 1] : 1);
        dfs(adj[u][i], multiply(mult, cur));
    }
}

void init(int N, int M, vector<int> P, vector<int> A){
    n = N;
    m = M;
    rep(i, 1, n + m){
        adj[P[i]].push_back(i);
    }

    rep(i, 0, m){
        state[i] = A[i];
    }

    predfs(0);
    dfs(0, 1);
    SegmentTree::build(1, 0, m - 1);
}

int count_ways(int L, int R){
    L -= n; R -= n;
    SegmentTree::update(1, 0, m - 1, L, R);
    return SegmentTree::get();
}

#ifdef LOCAL
int main(){
    srand(time(nullptr));
    mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

    auto random = [&](int l, int r){
        return uniform_int_distribution<int>(l, r)(rng);
    };

    for(int itest = 1; itest <= 1; ++itest){
        //random testcase
//        int N = random(1, 6), M = random(1, 20), Q = random(1, 5);
//        cout << "N = " << N << ", M = " << M << ", Q = " << Q << '\n';
//        vector<int> P(N + M, -1);
//        rep(i, 1, N + M){
//            P[i] = random(0, min(i - 1, N - 1));
//        }
//
//        vector<int> A(M);
//        rep(i, 0, M){
//            A[i] = random(0, 1);
//        }
//        cout << "Array P : "; rep(i, 0, N + M) cout << P[i] << ' '; cout << '\n';
//        cout << "Array A : "; rep(i, 0, M) cout << A[i] << ' '; cout << '\n';
//        init(N, M, P, A);
//        rep(i, 0, Q){
//            int L = random(0, M - 1), R = random(0, M - 1);
//            if(L > R) swap(L, R);
//            cout << "query : " << L << ' ' << R << '\n';
//            cout << count_ways(L, R) << '\n';
//        }

        //example testcase
        int N = 3, M = 4;
        vector<int> P(N + M);
        P = {-1, 0, 1, 2, 1, 1, 0};
        vector<int> A(M);
        A = {1, 0, 1, 0};
        init(N, M, P, A);
        cout << count_ways(3, 4) << '\n'; //should be 2
        cout << count_ways(4, 5) << '\n'; //should be 0
        cout << count_ways(3, 6) << '\n'; //should 6


    }

    return 0;
}
#endif //LOCAL

Compilation message (stderr)

circuit.cpp: In function 'bool minimize(T&, const T&)':
circuit.cpp:20:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
   20 |     if(a > b) return a = b, true; return false;
      |     ^~
circuit.cpp:20:35: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
   20 |     if(a > b) return a = b, true; return false;
      |                                   ^~~~~~
circuit.cpp: In function 'bool maximize(T&, const T&)':
circuit.cpp:25:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
   25 |     if(a < b) return a = b, true; return false;
      |     ^~
circuit.cpp:25:35: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
   25 |     if(a < b) return a = b, true; return false;
      |                                   ^~~~~~
circuit.cpp: In function 'void SegmentTree::build(int, int, int)':
circuit.cpp:77:25: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
   77 |             int mid = l + r >> 1;
      |                       ~~^~~
circuit.cpp: In function 'void SegmentTree::update(int, int, int, int, int)':
circuit.cpp:100:25: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
  100 |             int mid = l + r >> 1;
      |                       ~~^~~
#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...