Submission #967313

#TimeUsernameProblemLanguageResultExecution timeMemory
967313obokamanGame (IOI13_game)C++17
100 / 100
4411 ms134736 KiB
#include <iostream>
#include <vector>
#include <string>
#include "game.h"

using namespace std;

bool safecheck = false;
typedef long long ll;

struct Node {
  Node *l, *r;
  int x;
  ll val;
  int prio;
  ll gcd;
};

struct RowNode {
  RowNode *l, *r;
  int x;
  Node* row;
  Node* thick_row;
  int prio;
};

Node* row(RowNode* t) {
  return t ? t->row : nullptr;
}

Node* thick_row(RowNode* t) {
  return t ? t->thick_row : nullptr;
}

ll gcd(Node* t) {
  return t ? t->gcd : -1;
}
ll val(Node* t) {
  return t ? t->val : -1;
}

ll gcdrec(ll a, ll b) {
  return a == 0 ? b : gcdrec(b%a, a); 
}

ll gcd(ll a, ll b) {
  if (a == -1 || b == -1) return a == -1 ? b : a;
  return gcdrec(a, b);
}

Node* init_node(int x, ll val) {
  Node* t = new Node;
  t->l = t->r = nullptr;
  t->x = x;
  t->val = t->gcd = val;
  t->prio = rand();
  return t;
}

void update(Node* t) {
  if (t) {
    t->gcd = gcd(gcd(gcd(t->l), t->val), gcd(t->r));
  }
}

// x in l
void split(Node* t, Node*& l, Node*& r, int x) {
  if (!t) {
    l = r = nullptr;
  } else {
    if (x < t->x) {
      r = t;
      split(t->l, l, t->l, x);
    } else {
      l = t;
      split(t->r, t->r, r, x);
    }
    update(t);
  }
}

void merge(Node*& t, Node* l, Node* r) {
  if (!l || !r) {
    t = l ? l : r;
  } else {
    if (l->prio > r->prio) {
      t = l;
      merge(t->r, t->r, r);
    } else {
      t = r;
      merge(t->l, l, t->l);
    }
    update(t);
  } 
}

void update_x(Node*& t, int x, ll val) {
  Node* t1, *t2, *t3;
  split(t, t1, t2, x-1);
  split(t2, t2, t3, x);
  if (!t2) t2 = init_node(x, val);
  else t2->val = t2->gcd = val;
  merge(t, t1, t2);
  merge(t, t, t3);
}

ll gcdRS(Node* t, int R, int S) {
  Node* t1, *t2, *t3;
  split(t, t1, t2, R-1);
  split(t2, t2, t3, S);
  ll res = gcd(t2);
  merge(t, t1, t2);
  merge(t, t, t3);
  return res;
}


// gcd([x, \infy))
ll queryR(RowNode* t, int x, int R, int S) {
  if (!t) return -1;
  else if (x < t->x) {
    return gcd(gcdRS(thick_row(t->r), R, S),
	       gcd(gcdRS(row(t), R, S), queryR(t->l, x, R, S)));
  } else if (x == t->x) {
    return gcd(gcdRS(thick_row(t->r), R, S), gcdRS(row(t), R, S));
  } else return queryR(t->r, x, R, S);
}

// gcd((-\infy, x])
ll queryL(RowNode* t, int x, int R, int S) {
  if (!t) return -1;
  else if (x > t->x) {
    return gcd(gcdRS(thick_row(t->l), R, S),
	       gcd(gcdRS(row(t), R, S), queryL(t->r, x, R, S)));
  } else if (x == t->x) {
    return gcd(gcdRS(thick_row(t->l), R, S),
	       gcdRS(row(t), R, S));
  } else return queryL(t->l, x, R, S);
}

// gcd of [P, Q]x[R, S]
ll query(RowNode* t, int P, int Q, int R, int S) {
  if (!t) return -1;
  if (t->x < P) return query(t->r, P, Q, R, S);
  else if (t->x > Q) return query(t->l, P, Q, R, S);
  else {
    return gcd(gcdRS(row(t), R, S), gcd(queryR(t->l, P, R, S), queryL(t->r, Q, R, S)));
  }
}

ll find_gcd(Node* t, int Q) {
  if (!t) return -1;
  if (t->x == Q) return t->val;
  else {
    return find_gcd(Q < t->x ? t->l : t->r, Q);
  }
}

void pointUpdateThickrow(RowNode*& t, int Q) {
  // We don't need to fully recalculate thickrow, because only x=Q had
  // changed.
  Node* t1, *t2, *t3;
  split(t->thick_row, t1, t2, Q-1);
  split(t2, t2, t3, Q);
  ll newval = gcd( find_gcd(thick_row(t->l), Q),
		   gcd( find_gcd(thick_row(t->r), Q), find_gcd(t->row, Q)) );
  if (!t2) t2 = init_node(Q, newval);
  else t2->val = t2->gcd = newval;

  merge(t->thick_row, t1, t2);
  merge(t->thick_row, t->thick_row, t3);      
}

RowNode* find(RowNode* t, int P) {
  if (!t) {
    return nullptr;
  }
  else if (P < t->x) {
    return find(t->l, P);
  }
  else if (P > t->x) {
    return find(t->r, P);
  }
  else {
    return t;
  }
}

void copy(Node* src, Node*& dst) {
  if (!src) dst = nullptr;
  else {
    dst = new Node;
    copy(src->l, dst->l);
    copy(src->r, dst->r);
    dst->x = src->x;
    dst->val = src->val;
    dst->prio = src->prio;
    dst->gcd = src->gcd;
  }
}

Node* join(Node* t1, Node* t2) {
  Node* t;
  if (!t1 && !t2) t = nullptr;
  else if (!t1) copy(t2, t);
  else if (!t2) copy(t1, t);
  else {
    if (t1->prio < t2->prio) swap(t1, t2);
    t = new Node;
    Node* t2l, *t2x, *t2r;
    ll t2gcd = gcd(t2);
    split(t2, t2l, t2x, t1->x-1);
    split(t2x, t2x, t2r, t1->x);
    t->x = t1->x;
    t->val = gcd(val(t1), val(t2x));
    t->gcd = gcd(gcd(t1), t2gcd);
    t->prio = t1->prio;
    t->l = join(t1->l, t2l);
    t->r = join(t1->r, t2r);
    merge(t2, t2l, t2x);
    merge(t2, t2, t2r);
  }
  return t;
}

// P in l.
void split(RowNode* t, RowNode*& l, RowNode*& r, int P) {
  if (!t) {
    l = r = nullptr;
  } else {
    if (P < t->x) {
      r = t;
      split(t->l, l, t->l, P); 
    } else {
      l = t;
      split(t->r, t->r, r, P);
    }
    t->thick_row = join(join(thick_row(t->l), t->row), thick_row(t->r));
  }
}

void set_rec(RowNode*& t, int P, int Q, ll val, int prio) {
  if (!t) {
    t = new RowNode;
    t->l = t->r = nullptr;
    t->x = P;
    t->row = init_node(Q, val);
    t->prio = prio;
  } else {
    if (prio > t->prio) {
      // prio > 0 means we won't find P.
      RowNode* child = t;
      t = new RowNode;
      t->x = P;
      split(child, t->l, t->r, P);
      t->row = init_node(Q, val);
      // (Q,val) will be updated as part of pointUpdateThickrow
      t->thick_row = join(thick_row(t->l), thick_row(t->r));
      t->prio = prio;
    } else {
      if (P < t->x) set_rec(t->l, P, Q, val, prio);
      else if (P == t->x) update_x(t->row, Q, val);
      else set_rec(t->r, P, Q, val, prio);
    }
  }
  pointUpdateThickrow(t, Q);
}

void set(RowNode*& t, int P, int Q, ll val) {
  set_rec(t, P, Q, val, find(t, P) ? 0 : rand());
}


RowNode* globalt = nullptr;

void init(int R, int C) {
}
void update(int P, int Q, ll K) {
  set(globalt, P, Q, K);
}
ll calculate(int P, int Q, int R, int S) {
  ll res = query(globalt, P, R, Q, S);
  return res == -1 ? 0 : res;
}

//#include "game.h"
#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...