Submission #627197

#TimeUsernameProblemLanguageResultExecution timeMemory
627197model_codeDigital Circuit (IOI22_circuit)C++17
100 / 100
1398 ms33152 KiB
// correct/solution-ayaze-full.cpp
// O(N + M + Q log M)
#include "circuit.h"
#include <bits/stdc++.h>
using namespace std;

const int kMod = 1'000'002'022;

struct Node {
  bool lazy;
  int val[2];

  Node(int v0 = 0, int v1 = 0) {
    lazy = false;
    val[0] = v0;
    val[1] = v1;
  }

  void flip() {
    lazy = !lazy;
    swap(val[0], val[1]);
  }

  Node operator +(Node other) const {
    Node ret;
    for (int i = 0 ; i < 2 ; i++) {
      ret.val[i] = (val[i] + other.val[i]) % kMod;
    }
    return ret;
  }
};

struct SegmentTree {
  vector<Node> tree;
  int n;

  SegmentTree() {}
  SegmentTree(vector<pair<int, int>> initial_values) {
    n = initial_values.size();
    tree.resize(4 * n + 5);
    build(1, 0, n-1, initial_values);
  }

  void build(int id, int l, int r, vector<pair<int, int>> &initial_values) {
    if (l == r) {
      pair<int, int> val = initial_values[l];
      tree[id] = Node(val.first, val.second);
    } else {
      int m = (l + r) / 2;
      int chld = id << 1;

      build(chld, l, m, initial_values);
      build(chld+1, m+1, r, initial_values);
      tree[id] = tree[chld] + tree[chld+1];
    }
  }

  void propagate(int id) {
    if (!tree[id].lazy) return;
    for (int i = 0 ; i < 2 ; i++) {
      tree[2*id + i].flip();
    }
    tree[id].lazy = false;
  }

  void update(int l, int r) {
    update(1, 0, n-1, l, r);
  }

  void update(int id, int l, int r, int x, int y) {
    if (x <= l && r <= y) {
      tree[id].flip();
    } else {
      int m = (l + r) / 2;
      int chld = id << 1;

      propagate(id);
      if (x <= m) update(chld, l, m, x, y);
      if (y > m)  update(chld+1, m+1, r, x, y);
      tree[id] = tree[chld] + tree[chld+1];
    }
  }

  int query() {
    return tree[1].val[1];
  }
};

SegmentTree segment_tree;
vector<vector<int>> children;
vector<int> child_muls;
vector<int> contribs;
int N;

void DfsMuls(int v) {
  if (v >= N) {
    child_muls[v] = 1;
    return;
  }

  child_muls[v] = children[v].size();
  for (int nex : children[v]) {
    DfsMuls(nex);
    child_muls[v] = 1ll * child_muls[v] * child_muls[nex] % kMod;
  }
}

void DfsContrib(int v, int current_contrib) {
  if (v >= N) {
    contribs[v-N] = current_contrib;
    return;
  }

  vector<int> prefix_contrib(children[v].size()), suffix_contrib(children[v].size());
  for (int i = 0 ; i < static_cast<int>(children[v].size()) ; i++) {
    prefix_contrib[i] = child_muls[children[v][i]];
    if (i > 0) {
      prefix_contrib[i] = 1ll * prefix_contrib[i] * prefix_contrib[i-1] % kMod;
    }
  }
  for (int i = static_cast<int>(children[v].size())-1 ; i >= 0 ; i--) {
    suffix_contrib[i] = child_muls[children[v][i]];
    if (i+1 < static_cast<int>(children[v].size())) { 
      suffix_contrib[i] = 1ll * suffix_contrib[i] * suffix_contrib[i+1] % kMod;
    }
  }

  for (int i = 0 ; i < static_cast<int>(children[v].size()) ; i++) {
    int nex = children[v][i];
    int new_contrib = current_contrib;
    if (i > 0) {
      new_contrib = 1ll * new_contrib * prefix_contrib[i-1] % kMod;
    }
    if (i+1 < static_cast<int>(children[v].size())) { 
      new_contrib = 1ll * new_contrib * suffix_contrib[i+1] % kMod;
    }

    DfsContrib(nex, new_contrib);
  }
}

void init(int _N, int M, std::vector<int> P, std::vector<int> A) {
  N = _N;
  children.resize(N);
  contribs.resize(M);
  child_muls.resize(N+M);

  for (int i = 1 ; i < static_cast<int>(P.size()) ; i++) {
    children[P[i]].push_back(i);
  }
  DfsMuls(0);
  DfsContrib(0, 1);

  vector<pair<int, int>> initial_values;
  for (int i = 0 ; i < M ; i++) {
    pair<int, int> c = {0, contribs[i]};
    if (A[i] == 0) swap(c.first, c.second);
    initial_values.push_back(c);
  }

  segment_tree = SegmentTree(initial_values);
}

int count_ways(int L, int R) {
  segment_tree.update(L-N, R-N);
  return segment_tree.query();
}
#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...