C. Cellular Network
https://codeforces.com/contest/702/problem/C
题意:给定n个城市坐标和m个tower,问tower的最小半径是多少,可以罩住所有的城市。
思路:二分半径,优先更新上界。难点在于如何判定当前半径r是否可以包含所有城市,可以采取这个方法:求出m个区间,然后对区间进行合并,再依次考虑每个城市坐标,再次使用二分,看当前城市坐标是否属于某个区间即可。
总结:1、为了避免二分出现负数,对所有的坐标进行了偏移,很不错。2、二分的上界1e9不够用,为什么?因为偏移后最大的坐标应该是2e9,最小的是0,那么r应该至少为2e9,但是为了更无脑一点,直接开到最大即可。
3、在区间上二分的时候,要么找upper_bound的前一个数,要么直接lower_bound的时候,给城市的坐标 + 1,这样是为了找到区间左端点在城市坐标左边的区间,如果找不到,返回的应该是end。
inline void solve() {
int n, m;
cin >> n >> m;
constexpr int shift = 1e9;
vector<int> a(n);
for (auto& x : a) {
cin >> x;
x += shift;
}
vector<long long> tow(m);
for (auto& x : tow) {
cin >> x;
x += shift;
}
sort(tow.begin(), tow.end());
auto valid = [&](long long x) {
vector<pair<long long, long long>> b;
b.reserve(m);
for (int i = 0; i < m; ++i) {
pair<long long, long long> t = {tow[i] - x, tow[i] + x};
if (!b.empty() && t.first <= b.back().second) {
b.back().second = t.second;
}
else {
b.push_back(std::move(t));
}
}
bool ok = true;
for (int i = 0; i < n; ++i) {
auto it = lower_bound(b.begin(), b.end(), pair<long long, long long>{a[i] + 1, 0});
if (it != b.begin()) {
it = prev(it);
}
if (it->first <= a[i] && it->second >= a[i]) {
continue;
}
else {
ok = false;
break;
}
}
return ok;
};
long long l = 0, r = 1e18;
while (l < r) {
long long mid = (l + r) >> 1;
if (valid(mid)) {
r = mid;
}
else {
l = mid + 1;
}
}
cout << l << '\n';
}

浙公网安备 33010602011771号