Cod sursa(job #2591606)

Utilizator AlexPop28Pop Alex-Nicolae AlexPop28 Data 30 martie 2020 20:23:32
Problema Matrice 2 Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.73 kb
#include <bits/stdc++.h>
using namespace std;

struct RollbackDSU {
  struct State {
    int x_, x, rnk_x, y_, y, rnk_y;
  };

  int n, m;
  vector<int> dad, rnk;
  vector<State> ops;

  RollbackDSU(int n_, int m_) : n(n_), m(m_), dad(n * m, -1), rnk(n * m) {}

  int Find(int x) {
    if (dad[x] == -1) return x;
    return Find(dad[x]);
  }

  void Union(int x, int y) {
    int x_ = x, y_ = y;
    x = Find(x), y = Find(y);
    if (x == y) return;
    ops.emplace_back(State{x_, x, rnk[x], y_, y, rnk[y]});
    if (rnk[x] > rnk[y]) swap(x, y);
    dad[x] = y;
    rnk[y] += rnk[x] == rnk[y];
  }

  void Rollback(int x, int y) {
    if (ops.empty()) return;
    if (ops.back().x_ != x || ops.back().y_ != y) return;
    x = ops.back().x, y = ops.back().y;
    dad[x] = dad[y] = -1;
    rnk[x] = ops.back().rnk_x;
    rnk[y] = ops.back().rnk_y;
    ops.pop_back();
  }

  void Union(pair<int, int> x, pair<int, int> y) {
    Union(x.first * n + x.second, y.first * n + y.second);
  }

  int Find(pair<int, int> x) {
    return Find(x.first * n + x.second);
  }

  void Rollback(pair<int, int> x, pair<int, int> y) {
    Rollback(x.first * n + x.second, y.first * n + y.second); 
  }
};

const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};

int main() {
  ifstream cin("matrice2.in");
  ofstream cout("matrice2.out");

  int n, q; cin >> n >> q;
  vector<vector<int>> a(n, vector<int>(n));
  vector<tuple<int, int, int>> v;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      cin >> a[i][j];
      v.emplace_back(a[i][j], i, j);
    }
  }

  vector<pair<pair<int, int>, pair<int, int>>> qrs(q);
  for (int i = 0; i < q; ++i) {
    pair<int, int> a, b; cin >> a.first >> a.second >> b.first >> b.second;
    --a.first, --a.second, --b.first, --b.second;
    qrs[i] = make_pair(a, b);
  }

  sort(v.rbegin(), v.rend());
  RollbackDSU dsu(n, n);

  for (int i = 0; i < n * n; ++i) {
    int x, y; tie(ignore, x, y) = v[i];
    a[x][y] = i;
  }

  auto Mid = [](int x, int y) {
    return x + (y - x) / 2;
  };

  auto Check = [&](int idx) {
    pair<int, int> one, two; tie(one, two) = qrs[idx];
    return dsu.Find(one) == dsu.Find(two);
  };

  auto Inside = [&](int x, int y) {
    return 0 <= x && x < n &&
           0 <= y && y < n;
  };

  auto Activate = [&](int l, int r) {
    for (int i = l; i <= r; ++i) {
      int val, x, y; tie(val, x, y) = v[i];
      for (int dir = 0; dir < 4; ++dir) {
        int nx = x + dx[dir], ny = y + dy[dir];
        if (Inside(nx, ny) && a[nx][ny] < a[x][y]) {
          dsu.Union({x, y}, {nx, ny});
        }
      }
    }
  };

  auto Deactivate = [&](int l, int r) {
    for (int i = r; i >= l; --i) {
      int val, x, y; tie(val, x, y) = v[i];
      for (int dir = 3; dir >= 0; --dir) {
        int nx = x + dx[dir], ny = y + dy[dir];
        if (Inside(nx, ny) && a[nx][ny] < a[x][y]) {
          dsu.Rollback({x, y}, {nx, ny});
        }
      }
    }
  };

  vector<int> ans(q);

  function<void(int, int, vector<int>&)>
  Solve = [&](int lo, int hi, vector<int> &to_solve) {
    if (lo == hi) {
      for (int &idx : to_solve) {
        ans[idx] = get<0>(v[lo]);
      }
      return;
    }

    int mid = Mid(lo, hi);

    vector<int> lft, rgt;
    for (int &x : to_solve) {
      if (Check(x))
        lft.emplace_back(x);
      else
        rgt.emplace_back(x);
    }
    to_solve.clear();

    int lft_mid = Mid(lo, mid);
    Deactivate(lft_mid + 1, mid);
    Solve(lo, mid, lft);

    int rgt_mid = Mid(mid + 1, hi);
    Activate(mid + 1, rgt_mid);
    Solve(mid + 1, hi, rgt);
  };

  int mid = (n * n - 1) / 2;
  Activate(0, mid);
  
  vector<int> to_solve(q);
  iota(to_solve.begin(), to_solve.end(), 0);
 
  Solve(0, n * n - 1, to_solve);
  
  for (int i = 0; i < q; ++i) {
    cout << ans[i] << '\n';
  }
  cout << endl;
}