Submission #1356864

#TimeUsernameProblemLanguageResultExecution timeMemory
1356864TraianDanciuGame (IOI13_game)C++20
100 / 100
4089 ms59776 KiB
#include "game.h"
#include <algorithm>
#include <random>
#include <chrono>

using namespace std;

const int MAXUPD = 700000;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int vprio[MAXUPD], upd_idx, n;

long long gcd2(long long X, long long Y) {
  long long tmp;
  while (X != Y && Y != 0) {
    tmp = X;
    X = Y;
    Y = tmp % Y;
  }
  return X;
}

struct Treap {
  int key;
  long long val;
  int prio;
  long long gcd;
  Treap *l;
  Treap *r;
};

Treap *EMPTY_TREAP = new Treap {
  0, // key
  0, // val
  0, // prio
  0, // gcd
  nullptr, // l
  nullptr // r
};

struct Node {
  Treap *treap;
  Node *l;
  Node *r;

  Node() {
    treap = EMPTY_TREAP;
    l = r = nullptr;
  }
} *root;

Treap *valTreap(int key, long long val, int prio) {
  return new Treap {
    key, // key
    val, // val
    prio, // prio
    val, // gcd
    EMPTY_TREAP, // l
    EMPTY_TREAP // r
  };
}

void update(Treap *t) {
  if(t != EMPTY_TREAP) {
    t->gcd = gcd2(gcd2(t->l->gcd, t->val), t->r->gcd);
  }
}

pair<Treap*, Treap*> split(Treap *t, int key) {
  if(t == EMPTY_TREAP) {
    return {EMPTY_TREAP, EMPTY_TREAP};
  }

  if(t->key > key) {
    auto [l, r] = split(t->l, key);
    t->l = r;
    update(t);
    return {l, t};
  }

  auto [l, r] = split(t->r, key);
  t->r = l;
  update(t);
  return {t, r};
}

Treap *merge(Treap *l, Treap *r) {
  if(l == EMPTY_TREAP) {
    return r;
  }
  if(r == EMPTY_TREAP) {
    return l;
  }

  if(l->prio > r->prio) {
    l->r = merge(l->r, r);
    update(l);
    return l;
  }

  r->l = merge(l, r->l);
  update(r);
  return r;
}

void updateTreap(Treap *&t, int poz, long long val) {
  auto [t1, t2] = split(t, poz - 1);
  auto [t3, t4] = split(t2, poz);
  t = merge(t1, merge(valTreap(poz, val, vprio[upd_idx++]), t4));
}

long long queryTreap(Treap *&t, int st, int dr) {
  auto [t1, t2] = split(t, st - 1);
  auto [t3, t4] = split(t2, dr);
  long long ret = t3->gcd;
  t = merge(t1, merge(t3, t4));
  return ret;
}

long long get(Node *node, int poz) {
  if(node == nullptr) {
    return 0;
  }
  return queryTreap(node->treap, poz, poz);
}

void update(Node *&node, int left, int right, int lin, int col, long long val) {
  if(node == nullptr) {
    node = new Node;
  }
  if(left == right) {
    updateTreap(node->treap, col, val);
  } else {
    int middle = (left + right) / 2;
    if(lin <= middle) {
      update(node->l, left, middle, lin, col, val);
    } else {
      update(node->r, middle + 1, right, lin, col, val);
    }
    updateTreap(node->treap, col, gcd2(get(node->l, col), get(node->r, col)));
  }
}

long long query(Node *node, int left, int right, int linl, int linr, int coll, int colr) {
  if(node == nullptr) {
    return 0;
  }
  if(linl <= left && right <= linr) {
    return queryTreap(node->treap, coll, colr);
  }
  int middle = (left + right) / 2;
  long long answer = 0;
  if(linl <= middle) {
    answer = gcd2(answer, query(node->l, left, middle, linl, linr, coll, colr));
  }
  if(middle < linr) {
    answer = gcd2(answer, query(node->r, middle + 1, right, linl, linr, coll, colr));
  }
  return answer;
}

void init(int R, int C) {
  n = R;
  for(int i = 0; i < MAXUPD; i++) {
    vprio[i] = i;
  }
  shuffle(vprio, vprio + MAXUPD, rng);
  upd_idx = 0;
  root = nullptr;
}

void update(int P, int Q, long long K) {
  update(root, 0, n - 1, P, Q, K);
}

long long calculate(int P, int Q, int U, int V) {
  return query(root, 0, n - 1, P, U, Q, V);
}
#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...