Submission #634605

#TimeUsernameProblemLanguageResultExecution timeMemory
634605JeanBombeur디지털 회로 (IOI22_circuit)C++17
100 / 100
1088 ms42504 KiB
#include "circuit.h"
#include <vector>
#include <cstdio>
using namespace std;

//  <|°_°|>

//  Jean Bombeur & M. Broccoli

//  The hardest choices require the strongest wills

//  What is better - to be born good, or to overcome your evil nature with great effort ?

const int MOD = (1000002022);
const int MAX_NODES = (2e5);
const int LOG = (17);
const int SIZE = (1 << LOG);

struct node {
    int val = 0, inv = 0, flag = 0;
};

template <class T = int, class F = int>
struct segment_tree {
    vector <T> Tree;
    vector <F> Flags;
    int size = 0, log_max = 0;
    
    // =================== TO FILL ====================
    
    // put here your favorite operation on nodes like min, max, gcd ...
    inline T combine(T left_value, T right_value) {
        return {(left_value.val + right_value.val) % MOD, (left_value.inv + right_value.inv) % MOD, 0};
    }
    
    bool using_lazy = true;  // set to true if you want to enable lazy flags
    
    // put here your favorite operation on flags
    inline F combine_flags(F old_flag, F new_flag) {
        return old_flag ^ new_flag;
    }
    
    bool flags_commute = true;  // set to true if combine_flags is commutative (speeds up a little)
    
    // put here how values and flags interact
    inline T combine_with_flag(T value, F flag) {
        return flag ? (T){value.inv, value.val, 0} : value;
    }
    
    T start_value = {0, 0, 0};  // put here the default value of a node
    T null_value = {0, 0, 0};  // put here the identity value of combine
    F null_flag = 0;  // put here the default value of a flag
    
    // make sure that operator != is defined for flags !
    
    // ================= FOR DEBUG ====================
    
    // put here what you'd like to print about the nodes
    void print_value(T value) {
        printf("%d", value);
        return;
    }
    
    // put here what you'd like to print about the flags
    void print_flag(F flag) {
        printf("%d", flag);
        return;
    }
    
    // ======== DO NOT TOUCH AFTER THIS LINE ==========
    
    // remember to call this at the start !
    // n doesn't need to be a power of two
    void set_to_size(int n) {
        Tree.resize(2 * n, start_value);
        if (using_lazy)
            Flags.resize(n, null_flag);
        size = n;
        log_max = 32 - __builtin_clz(n);
        return;
    }
    
    // destroys everything : ready to be used again !
    void clear() {
        Tree.clear();
        Flags.clear();
        size = log_max = 0;
        return;
    }
    
    // turns an array of exactly size elements into a segtree : equivalent to updating each element but faster
    // void build(vector <T> &Array) {  // you may use this instead
    void build(T* Array) {
        for (int i = 0; i < size; i ++)
            Tree[i + size] = Array[i];
        for (int i = size - 1; i; i --)
            Tree[i] = combine(Tree[i << 1], Tree[(i << 1) ^ 1]);
        return;
    }
    
    // combines flag to node index
    void put_flag(int index, F flag) {
        Tree[index] = combine_with_flag(Tree[index], flag);
        if (index < size)
            Flags[index] = combine_flags(Flags[index], flag);
        return;
    }
    
    // pushes all flags above node index
    void push(int index) {
        for (int h = log_max; h; h --)
        {
            int p = index >> h;
            if (Flags[p] != null_flag)
            {
                put_flag(p << 1, Flags[p]);
                put_flag((p << 1) ^ 1, Flags[p]);
                Flags[p] = null_flag;
            }
        }
        return;
    }
    
    // updates all values above node index
    void pull(int index) {
        for (index >>= 1; index; index >>= 1)
            Tree[index] = combine_with_flag(combine(Tree[index << 1], Tree[(index << 1) ^ 1]), Flags[index]);
        return;
    }
    
    // sets the index-th element to value (zero-based)
    void set(int index, T value) {
        index += size;
        if (using_lazy)
        {
            push(index);
            Tree[index] = value;
            pull(index);
            return;
        }
        Tree[index] = value;
        for (index >>= 1; index; index >>= 1)
            Tree[index] = combine(Tree[index << 1], Tree[(index << 1) ^ 1]);
        return;
    }
    
    // returns the value of the index-th element (zero-based)
    T get(int index) {
        index += size;
        if (using_lazy)
            push(index);
        return Tree[index];
    }
    
    // combines lazily a flag to the range [left, right[  (zero-based)
    void range_add(int left, int right, F flag) {
        left += size, right += size;
        if (!flags_commute)
            push(left), push(right - 1);
        for (int l = left, r = right; l < r; l >>= 1, r >>= 1)
        {
            if (l & 1)
                put_flag(l ++, flag);
            if (r & 1)
                put_flag(-- r, flag);
        }
        pull(left), pull(right - 1);
        return;
    }
    
    // returns combine of all elements in range [left, right[  (zero-based)
    T range_op(int left, int right) {
        left += size, right += size;
        if (using_lazy)
            push(left), push(right - 1);
        T left_ans = null_value, right_ans = null_value;
        for (; left < right; left >>= 1, right >>= 1)
        {
            if (left & 1)
                left_ans = combine(left_ans, Tree[left ++]);
            if (right & 1)
                right_ans = combine(Tree[-- right], right_ans);
        }
        return combine(left_ans, right_ans);
    }
    
    // prints the tree rotated 90 degrees left
    void print(int a = 1, int p = 0) {
        if (a >= 2 * size)
            return;
        if (a == 1)
        {
            for (int i = 0; i < 60; i ++)
                printf("=");
            printf("\n");
        }
        print((a << 1) ^ 1, p + 1);
        for (int i = 0; i < p; i ++)
            printf("\t");
        print_value(Tree[a]);
        if (using_lazy)
        {
            printf(" / ");
            if (a < size)
                print_flag(Flags[a]);
        }
        printf("\n");
        print(a << 1, p + 1);
        if (a == 1)
        {
            for (int i = 0; i < 60; i ++)
                printf("=");
            printf("\n");
        }
        return;
    }
};

vector <int> Adj[MAX_NODES];

long long Sz[MAX_NODES];

segment_tree <node> Segt;
node Sources[MAX_NODES];

int nbThresholds;

int DfsSz(int node) {
    Sz[node] = Adj[node].size() + Adj[node].empty();
    for (int dest : Adj[node])
        Sz[node] *= DfsSz(dest), Sz[node] %= MOD;
    return Sz[node];
}

void DfsSet(int node, long long value) {
    if (Adj[node].empty())
        Sources[node - nbThresholds] = {0, (int)value, 0};
    vector <long long> ProdPref (1, 1);
    vector <long long> ProdSuff (1, 1);
    int sz = Adj[node].size();
    for (int i = 0; i < sz; i ++)
    {
        ProdPref.push_back((ProdPref.back() * Sz[Adj[node][i]]) % MOD);
    }
    for (int i = sz - 1; i >= 0; i --)
    {
        ProdSuff.push_back((ProdSuff.back() * Sz[Adj[node][i]]) % MOD);
    }
    for (int i = 0; i < sz; i ++)
    {
        DfsSet(Adj[node][i], (((value * ProdPref[i]) % MOD) * ProdSuff[sz - i - 1]) % MOD);
    }
    return;
}

void init(int nbNodes, int nbSources, vector <int> Parent, vector <int> States) {
    nbThresholds = nbNodes;
    Segt.set_to_size(nbSources);
    for (int i = 1; i < nbThresholds + nbSources; i ++)
    {
        Adj[Parent[i]].push_back(i);
    }
    DfsSz(0);
    DfsSet(0, 1);
    for (int i = 0; i < nbSources; i ++)
    {
        if (States[i])
            swap(Sources[i].val, Sources[i].inv);
    }
    Segt.build(Sources);
    return;
}

int count_ways(int left, int right) {
    Segt.range_add(left - nbThresholds, (++ right) - nbThresholds, 1);
    return Segt.Tree[1].val;
}
#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...