题意就是我们询问区间 他会给第二大的数的位置。
琢磨下 可以想到 [L,x ,R] 。。
我们可以猜 最大值 在左边
我们再次进行询问 [L,x] 如果答案还是x 说明最大值肯定在左边 反之。。
但是这样还不够。还是会超出次数。
他这里进行了一种很巧妙的二分思想。。
我们一直保留x的位置。。作为边界。
我们对L->x这个区间反复进行二分询问 [mid,x];
#include <bits/stdc++.h>
using namespace std;
#define easy_code ios::sync_with_stdio(0)
#define endl '\n'
#define int long long
#define ar array<int, 2>
#define arr array<int, 3>
int T, n, m, k, inf = 1e18;
int mod = 998244353; // 1e9+7;
const int N = 201314;
bool query(int l, int r, int x)
{
cout << "? " << l << " " << r << endl;
int t;
cin >> t;
return t == x;
};
signed main()
{
easy_code;
#ifdef DEBUG
freopen("../1.in", "r", stdin);
#endif
cin >> n;
int l = 1, r = n;
cout << "? " << l << " " << r << endl;
int x;
cin >> x;
//下面两套二分框架是有区别的
//核心区别在于 当合法的时候 我们是要把mid位置保留给L 还是R?
if (x > 1 && query(1, x, x))
{
r = x - 1;
while (l < r)//
{
int mid = (l + r + 1) >> 1;
if (query(mid, x, x))
l = mid;//因为这时候x在右边 所以当合法时候我们要保留mid 就把L边界移动到mid为位置。
else
r = mid - 1;
}
}
else
{
l = x + 1;
while (l < r)
{
int mid = (l + r) >> 1;
if (query(x, mid, x))
r = mid;//这变是x在左边界的位置。所以当合法的时候我们要把右边界移动到mid为止 不能-1 因为mid位置是有可能为最大值的。
else
l = mid + 1;
}
}
cout << "! " << l;
};