tags
数据结构
二分
树状数组
排序
中文题面
Radio stations
一共有 n 个电台,对于每个电台 i 有三个参数:
x
i
x_i
xi,
r
i
r_i
ri,
f
i
f_i
fi,分别指它的一维坐标、作用半径和频率。如果两个电台的频率差值在 k 内,并且它们的作用范围都能覆盖到彼此,那么就称这两个电台相互干扰。问这 n 个站台中相互干扰的站台有多少对。
思路
可以注意到的是 k k k 的取值范围较小,我们可以考虑按照频率 f f f 给点分类,同频率的在一组,当选定某个点时,枚举与它距离最多为 k k k 的频率,从而找到答案。两个可以互相到达的点只要其中 r r r 更小的点能到达 r r r 更大的点即可,我们考虑按照 r r r 的升序处理每个点,对于已处理过的点把它禁掉,这样由于我们每次选取的都是当前 r r r 最小的点,一旦有点在 [ x − r , x + r ] [x - r, x + r] [x−r,x+r] 的范围内(设当前点坐标 x x x),则二者互相可达。那么对于枚举到的相近频率,我们二分查找在 [ x − r , x + r ] [x - r, x + r] [x−r,x+r] 的点数,即为当前点能组成的相互干扰节点(坏节点)的对数。已经处理过的当前点需要禁掉(不然会重复),由于直接从数组中删除单次复杂度为 O ( n ) O(n) O(n),我们考虑用树状数组表示,这样单次删除时间复杂度为 O ( l o g n ) O(log n) O(logn),本代码总时间复杂度为 O ( 20 ∗ n ∗ l o g n ) O(20 * n * logn) O(20∗n∗logn)
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define N (int)1e5 + 5
#define pdd pair<double, double>
#define pii pair<int, int>
#define lowbit(x) (x & -x)
int x, n, k, l, r;
struct node {
int x,r, f;
} all[N];
bool cmp(const node& a, const node& b) {
return a.r < b.r;
}
vector<int> f[10005], ban[10005];
int sum(int i, int x) {
int ans = 0;
while (x) {
ans += ban[i][x];
x -= lowbit(x);
}
return ans;
}
void add(int i, int x, int k) {
while (x < ban[i].size()) {
ban[i][x] += k;
x += lowbit(x);
}
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> k;
int cnt = 0;
for (int i = 1; i <= 1e4; i++) f[i].push_back(0), ban[i].push_back(0);
for (int i = 1; i <= n; i++) {
cin >> all[i].x >> all[i].r >> all[i].f;
f[all[i].f].push_back(all[i].x);
ban[all[i].f].push_back(0);
}
sort(all + 1, all + 1 + n, cmp);
for (int i = 1; i <= 1e4; i++) sort(f[i].begin(), f[i].end());
for (int i = 1; i <= n; i++) {
// cout << all[i].x << '\n';
for (int j = max(1ll, all[i].f - k); j <= min(10000ll, all[i].f + k); j++) {
// all[i].x - r, all[i].x + r
l = lower_bound(f[j].begin() + 1, f[j].end(), all[i].x - all[i].r) - f[j].begin();
r = upper_bound(f[j].begin() + 1, f[j].end(), all[i].x + all[i].r) - f[j].begin() - 1;
if (1 <= l < f[j].size() && 1 <= r < f[j].size() && l <= r) {
cnt += r - l + 1;
cnt -= sum(j, r) - sum(j, l - 1);
}
// cout << j << ' ' << l << ' ' << r << '\n';
}
int idx = lower_bound(f[all[i].f].begin() + 1, f[all[i].f].end(), all[i].x) - f[all[i].f].begin();
add(all[i].f, idx, 1);
cnt--;
}
cout << cnt << '\n';
return 0;
}