B. Searching Rectangles - Codeforces Round 371 (Div. 1)
Solutions Codeforces 交互 二分
Lastmod: 2024-07-31 周三 22:09:50

https://codeforces.com/contest/713/problem/B

题目大意

给定 $n \times n \ (n \le 2^16)$ 个方格区域,上面有两个未知的,不相交的,平行于坐标轴的矩形。 可以给出不超过 $200$ 次平行于坐标轴的矩形的询问(左上右下坐标),每次会给出完全包含在询问区域中的矩形个数。 最后需要回答每个矩形的左上右下角的位置

简要题解

对于两个不相交的矩形,必有一条水平线或竖直线分割它们。我们可以尝试分别从上下边界二分这条线。如果二分的位置不重合则说明已经将两个矩形分开,则对单个矩形单独二分四个边界即可。如果二分的位置重合,则说明两个矩形并不是上下排布,而是左右排布的,重新进行二分即可。

这里每次二分花费为 $16$ 左右,一共最多需要进行 $12$ 次二分,不会超出边界(当然实际上下面代码可以复用一些二分的结果,可以做到更低)。

复杂度

$T$:$O(\log(N))$

$S$:$O(1)$

代码实现

#include <bits/stdc++.h>
using namespace std;

int io_=[](){ ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();

using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
using VI = vector<int>;
using MII = map<int, int>;

template<typename T> void cmin(T &x,const T &y) { if(y<x) x=y; }
template<typename T> void cmax(T &x,const T &y) { if(x<y) x=y; }
template<typename T> bool ckmin(T &x,const T &y) { 
    return y<x ? (x=y, true) : false; }
template<typename T> bool ckmax(T &x,const T &y) { 
    return x<y ? (x=y, true) : false; }
template<typename T> void cmin(T &x,T &y,const T &z) {// x<=y<=z 
    if(z<x) { y=x; x=z; } else if(z<y) y=z; }
template<typename T> void cmax(T &x,T &y,const T &z) {// x>=y>=z
    if(x<z) { y=x; x=z; } else if(y<z) y=z; }

// mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
// mt19937_64 rnd_64(chrono::system_clock::now().time_since_epoch().count());

/*
---------1---------2---------3---------4---------5---------6---------7---------
1234567890123456789012345678901234567890123456789012345678901234567890123456789
*/

int query(int x1, int y1, int x2, int y2) {
  cout << "? " << x1 << ' ' << y1 << ' ' << x2 << ' ' << y2 << endl;
  int ans; cin >> ans;
  return ans;
}

void checktop(int& x1, int y1, int x2, int y2, int t) {
  int l = x1 + 1, r = x2;
  int ans = x1, mid;
  while (l <= r) {
    mid = (l + r) >> 1;
    if (query(mid, y1, x2, y2) >= t) {
      ans = mid;
      l = mid + 1;
    } else {
      r = mid - 1;
    }
  }
  x1 = ans;
}

void checkbot(int x1, int y1, int& x2, int y2, int t) {
  int l = x1, r = x2 - 1;
  int ans = x2, mid;
  while (l <= r) {
    mid = (l + r) >> 1;
    if (query(x1, y1, mid, y2) >= t) {
      ans = mid;
      r = mid - 1;
    } else {
      l = mid + 1;
    }
  }
  x2 = ans;
}

void checklft(int x1, int& y1, int x2, int y2, int t) {
  int l = y1 + 1, r = y2;
  int ans = y1, mid;
  while (l <= r) {
    mid = (l + r) >> 1;
    if (query(x1, mid, x2, y2) >= t) {
      ans = mid;
      l = mid + 1;
    } else {
      r = mid - 1;
    }
  }
  y1 = ans;
}

void checkrgt(int x1, int y1, int x2, int& y2, int t) {
  int l = y1, r = y2 - 1;
  int ans = y2, mid;
  while (l <= r) {
    mid = (l + r) >> 1;
    if (query(x1, y1, x2, mid) >= t) {
      ans = mid;
      r = mid - 1;
    } else {
      l = mid + 1;
    }
  }
  y2 = ans;
}

void solve() {
  int n; cin >> n;
  int x1 = 1, y1 = 1, x2 = n, y2 = n;
  // checktop(x1, y1, x2, y2, 2);
  // checkbot(x1, y1, x2, y2, 2);
  // checklft(x1, y1, x2, y2, 2);
  // checkrgt(x1, y1, x2, y2, 2); // 不用在最开始二分边界

  int x11 = x1, y11 = y1, x12 = x2, y12 = y2;
  int x21 = x1, y21 = y1, x22 = x2, y22 = y2;

  checkbot(x11, y11, x12, y12, 1);
  checktop(x21, y21, x22, y22, 1);

  if (x12 >= x21) {
    x12 = x2;
    x21 = x1;
    checklft(x11, y11, x12, y12, 1);
    checkrgt(x21, y21, x22, y22, 1);
  }

  checkbot(x11, y11, x12, y12, 1);
  checktop(x11, y11, x12, y12, 1);
  checklft(x11, y11, x12, y12, 1);
  checkrgt(x11, y11, x12, y12, 1);
  checktop(x21, y21, x22, y22, 1);
  checkbot(x21, y21, x22, y22, 1);
  checkrgt(x21, y21, x22, y22, 1);
  checklft(x21, y21, x22, y22, 1);

  cout << "! " << x11 << ' ' << y11 << ' ' << x12 << ' ' << y12 << ' '
      << x21 << ' ' << y21 << ' ' << x22 << ' ' << y22 << endl;
}

int main() {
  int t = 1; 
  // cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}

Prev: C. The Values You Can Make - Codeforces Round 360 (Div.1)
Next: C. Sonya and Problem Wihtout a Legend - Codeforces Round 371 (Div. 1)