CF762E Radio stations

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] [xr,x+r] 的范围内(设当前点坐标 x x x),则二者互相可达。那么对于枚举到的相近频率,我们二分查找在 [ x − r , x + r ] [x - r, x + r] [xr,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(20nlogn)

代码

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值