Cod sursa(job #1813654)

Utilizator stoianmihailStoian Mihail stoianmihail Data 23 noiembrie 2016 09:29:47
Problema A+B Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 8.81 kb
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <math.h>

#define MAX_Q 250000
#define MAX_TREE 32768
#define MAX_U 22000
#define NIL -1

#define ll long long

/** Algoritmul lui Euclid. **/
ll int gcd(ll int a, ll int b) {
  return b ? gcd(b, a % b) : a;
}

ll int join(ll int l, ll int r) {
  if (l == 1LL) {
    return r;
  } else if (r == 1LL) {
    return l;
  } else {
    return gcd(l, r);
  }
}

/** Structura pentru o celula. **/
struct pair {
  int l, c;

  pair() {

  }

  pair(int l, int c) {
    this -> l = l;
    this -> c = c;
  }

  bool operator == (const pair &other) const {
    return this -> l == other.l && this -> c == other.c;
  }

  bool operator != (const pair &other) const {
    return !(*this == other);
  }

  bool operator < (const pair &other) const {
    return this -> c < other.c || (this -> c == other.c && this -> l < other.l);
  }

  bool operator <= (const pair &other) const {
    return *this < other || *this == other;
  }
};

inline int get(int x) {
  return 1 << ((int)log2(x) + 1);
}

/** Nodul din arborele de intervale principal. **/
class segTree {
public:
  int n, shl;
  pair *sorted;
  ll int *tree;
  ll int local;
  char check, *seen;  // daca am vazut vreo valoare "1".

  segTree() {

  }

  /** Umple arborele de intervale cu "1". **/
  void fill(int u, int left, int right) {
    this -> tree[u] = 1;
    if (left != right) {
      int mid = (left + right) / 2;
      this -> fill(2 * u, left, mid);
      this -> fill(2 * u + 1, mid + 1, right);
    }
  }

  /** Initializarea arborelui cu ajutorul vectorului sortat "take". **/
  void init(const int l, const int *take) {
    this -> n = take[0];
    this -> shl = get(this -> n);
    this -> sorted = (pair*)calloc(this -> n, sizeof(pair));
    this -> tree = (ll int*)calloc(2 * get(this -> n) + 1, sizeof(ll int));
    this -> seen = (char*)calloc(2 * get(this -> n) + 1, sizeof(char));

    int i;
    for (i = 0; i < this -> n; i++) {
      this -> sorted[i] = pair(l, take[i + 1]);
    }
    fill(1, 0, this -> n - 1);
  }

  /** Cautare binara cu proprietatea "set". **/
  int find(pair search, int set) {
    int pas = this -> shl;
    int x = -1;

    while (pas) {
      if (x + pas < this -> n && this -> sorted[x + pas] <= search) {
        x += pas;
      }
      pas >>= 1;
    }
    return x + (this -> sorted[x] != search) * set;
  }

  /** Update normal. **/
  void update(int u, int left, int right, const int pos, const ll int val, char look) {
    if (left == right) {
      this -> tree[u] = val;
      this -> seen[u] = look;
      return;
    }

    int mid = (left + right) / 2;
    if (pos <= mid) {
      update(2 * u, left, mid, pos, val, look);
    } else {
      update(2 * u + 1, mid + 1, right, pos, val, look);
    }
    this -> tree[u] = join(this -> tree[2 * u], this -> tree[2 * u + 1]);
    this -> seen[u] = this -> seen[2 * u] | this -> seen[2 * u + 1];
  }

  /** Query normal. **/
  void query(int u, int left, int right, int a, int b) {
    if (a <= left && right <= b) {
      local = join(local, this -> tree[u]);
      check |= this -> seen[u];
      return;
    }

    int mid = (left + right) / 2;
    if (a <= mid) {
      query(2 * u, left, mid, a, b);
    }
    if (b > mid) {
      query(2 * u + 1, mid + 1, right, a, b);
    }
  }

public:
  void update(int l, int c, ll int val) {
    update(1, 0, this -> n - 1, find(pair(l, c), 0), val + (val == 0), val == 1);
  }

  ll int query(int a, int b, int *flag) {
    local = 1;
    check = 0;
    query(1, 0, this -> n - 1, find(pair(NIL, a), 1), find(pair(INT_MAX, b), 0));
    *flag |= check;
    return local;
  }

  /** Uneste doua noduri in "result". **/
  segTree operator + (const segTree &other) {
    int i = 0, j = 0, k = 0;
    segTree result;

    result.n = this -> n + other.n;
    result.shl = get(result.n);
    result.sorted = (pair*)calloc(result.n, sizeof(pair));
    result.tree = (ll int*)calloc(2 * get(result.n) + 1, sizeof(ll int));
    result.seen = (char*)calloc(2 * get(result.n) + 1, sizeof(char));

    while (i < this -> n && j < other.n) {
      if (this -> sorted[i] < other.sorted[j]) {
        result.sorted[k++] = this -> sorted[i++];
      } else {
        result.sorted[k++] = other.sorted[j++];
      }
    }
    while (i < this -> n) {
      result.sorted[k++] = this -> sorted[i++];
    }
    while (j < other.n) {
      result.sorted[k++] = other.sorted[j++];
    }
    result.fill(1, 0, result.n - 1);
    return result;
  }
};

struct save {
  char task;
  int a, b, c, d;
  ll int val;
};

int N, R, C;
ll int answer, now;
segTree tree[2 * MAX_TREE + 1];
save query[MAX_Q + MAX_U];

int size, shl, flag;
int normalize[MAX_U];

int **list;
int count[MAX_U];

/** quick-sort. **/
template <class data> void sort(data *val, int begin, int end) {
  int b = begin, e = end;
  data tmp, pivot = val[(b + e) / 2];

  while (b <= e) {
    while (val[b] < pivot) {
      b++;
    }
    while (pivot < val[e]) {
      e--;
    }
    if (b <= e) {
      tmp = val[b];
      val[b++] = val[e];
      val[e--] = tmp;
    }
  }
  if (begin < e) {
    sort(val, begin, e);
  }
  if (b < end) {
    sort(val, b, end);
  }
}

/** Elimina duplicatele. **/
void peek() {
  int i, buff = 1;

  for (i = 1; i < size; i++) {
    if (normalize[i] != normalize[buff - 1]) {
      normalize[buff++] = normalize[i];
    }
  }
  size = buff;
}

/** Cautare binara cu proprietate. **/
int binSearch(int val, int set) {
  int pas = shl;
  int x = -1;

  while (pas) {
    if (x + pas < size && normalize[x + pas] <= val) {
      x += pas;
    }
    pas >>= 1;
  }
  return x + (val != normalize[x]) * set;
}

/** Construieste blocurile de memorie. **/
void alloc() {
  int i;

  list = (int**)calloc(size, sizeof(int*));
  for (i = 0; i < size; i++) {
    list[i] = (int*)calloc(count[i] + 1, sizeof(int));
  }
  for (i = 0; i < N; i++) {
    if (query[i].task == 1) {
      list[query[i].a][++list[query[i].a][0]] = query[i].b;
    }
  }
  for (i = 0; i < size; i++) {
    if (list[i][0] > 1) {
      sort(list[i], 1, list[i][0]);
    }
  }
}

void build(int u, int left, int right) {
  if (left == right) {
    tree[u].init(left, list[left]);
    return;
  }

  int mid = (left + right) / 2;
  build(2 * u, left, mid);
  build(2 * u + 1, mid + 1, right);
  tree[u] = tree[2 * u] + tree[2 * u + 1];
}

void update(int u, int left, int right, const int l, const int c, const ll int val) {
  tree[u].update(l, c, val);
  if (left == right) {
    return;
  }

  int mid = (left + right) / 2;
  if (l <= mid) {
    update(2 * u, left, mid, l, c, val);
  } else {
    update(2 * u + 1, mid + 1, right, l, c, val);
  }
}

void ask(int u, int left, int right, const int l, const int l0, const int c, const int c0) {
  if (flag) {
    return;
  }
  if (l <= left && right <= l0) {
    now = tree[u].query(c, c0, &flag);
    if (flag != 1) {
      answer = join(answer, now);
    }
    return;
  }

  int mid = (left + right) / 2;
  if (l <= mid) {
    ask(2 * u, left, mid, l, l0, c, c0);
  }
  if (l0 > mid) {
    ask(2 * u + 1, mid + 1, right, l, l0, c, c0);
  }
}

int main(void) {
  int i;
  FILE *f = fopen("game.in", "r");

  /** Citeste intrebarile. **/
  fscanf(f, "%d %d %d", &R, &C, &N);
  for (i = 0; i < N; i++) {
    fscanf(f, "%d", &query[i].task);
    if (query[i].task == 1) {
      fscanf(f, "%d %d %lld", &query[i].a, &query[i].b, &query[i].val);
      normalize[size++] = query[i].a;
    } else {
      fscanf(f, "%d %d %d %d", &query[i].a, &query[i].b, &query[i].c, &query[i].d);
    }
  }
  fclose(f);

  /** Sorteaza si scoate dublurile. **/
  sort(normalize, 0, size - 1);
  peek();

  /** Construieste "shl". **/
  shl = get(size);

  /** Normalizeaza intrebarile. **/
  for (i = 0; i < N; i++) {
    if (query[i].task == 1) {
      query[i].a = binSearch(query[i].a, 0);
      count[query[i].a]++;
    } else {
      query[i].a = binSearch(query[i].a, 1);
      query[i].c = binSearch(query[i].c, 0);
    }
  }

  /** Construieste liniile. **/
  alloc();
  build(1, 0, size - 1);

  /** Raspunde la intrebari. **/
  freopen("game.out", "w", stdout);
  for (i = 0; i < N; i++) {
    if (query[i].task == 1) {
      update(1, 0, size - 1, query[i].a, query[i].b, query[i].val);
    } else {
      flag = 0;
      answer = 1;
      ask(1, 0, size - 1, query[i].a, query[i].c, query[i].b, query[i].d);
      if (flag) {
        fprintf(stdout, "1\n");
      } else {
        if (answer == 1) {
            fprintf(stdout, "0\n");
        } else {
            fprintf(stdout, "%lld\n", answer);
        }
      }
    }
  }
  fclose(stdout);
  return 0;
}