cf104G AI robots - CDQ分治 + 单调队列 + 树状数组

传送门
很有限制的一道题
对于任意机器人,存在一个初始位置点和一个观测半径以及iq值
任意两个机器人,如果都能观测到对方且iq值差距不大于k,那么可以进行交流。求交流的机器人有几对。

每个人有2个属性,可以想到是CDQ分治。
然后对于观测来说,只需要按照观测半径先进行排序,那么在CDQ分治里面,你去找到一个点时,这个点能观测到之前的点,那么之前的点肯定也能观测到这个点。
那么接下来就处理半径问题和iq问题。

我们考虑在CDQ分治里的排序。我们用iq进行排序,位置用树状数组维护。
因为考虑到有限制,即\([mid + 1, r]\)上的点要去找iq值都符合的点,因为iq值是在CDQ分治里排序的,那么也就是说对于这个区间里的点对应的最小iq值下标和最大iq值下标是单调的,也就是说随着我iq值的增加,查询谁能匹配的那个区间是单调的,向右增加的,但都在\([l, mid]\)里,那么就考虑用单调队列的思想去搞。找到两个区间就行了。
而在找的过程,同时维护下树状数组,把点的坐标加进去。
最后查询时就是看我的观测区间里面有多少个点就行了。

对于有限制的区间,可以先想想这个区间是否的单调递增,即l,r只能向右边移动的,然后用单调队列思想。
CQD应该考虑维度多少,属性有什么,以及第一维度按照什么进行排序,第二维度按照上面进行排序,第三维度维护什么之类的。
然后要注意的是第三维度即树状数组维护的值都要离散化的。

#include <bits/stdc++.h>
using namespace std;
int n, k;
template<typename T = long long> inline T read() {
    T s = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
    while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
    return s * f;
}
const int N = 4e5 + 5, M = 1e6 + 5, MOD = 1e9 + 7, CM = 998244353, INF = 0x3f3f3f3f;
int b[N];
struct Operation{
    int x, rr, iq, l, r;
} q[N];
struct BIT{
    int c[N];
    int lowbit(int x) {return x & (-x);}
    void add(int pos, int val) {for(; pos < N; pos += lowbit(pos)) c[pos] += val;}
    int sum(int pos) { int res = 0; for(; pos; pos -= lowbit(pos)) res += c[pos]; return res;}
    int query(int l, int r) {return sum(r) - sum(l - 1);}
    void clear(int pos) {for(; pos < N; pos += lowbit(pos)) c[pos] = 0;}
} bit;
long long ans = 0;
void CDQ(int l, int r){
    if(l == r) return;
    int mid = (l + r) >> 1;
    CDQ(l, mid), CDQ(mid + 1, r);
    int lp = l, rp = l;
    for(int i = mid + 1; i <= r; i++) { // 贡献在[mid + 1, r]
        while(lp <= mid && q[lp].iq < q[i].iq - k) bit.add(q[lp++].x, -1);
        while(rp <= mid && q[rp].iq <= q[i].iq + k) bit.add(q[rp++].x, 1);
        ans += bit.query(q[i].l, q[i].r);
    }
    for(int i = lp; i < rp; i++) bit.add(q[i].x, -1);
    sort(q + l, q + r + 1, [](Operation &a, Operation &b){
        return a.iq < b.iq;
    }); 
}
int all_num = 0;
int main(){
    n = read(), k = read();
    for(int i = 1; i <= n; i++) {
        int x = read(), r = read(), iq = read();
        q[i] = Operation{x, r, iq, 0, 0};
        b[++all_num] = x;
        b[++all_num] = x - r;
        b[++all_num] = x + r;
    }
    sort(b + 1, b + all_num + 1);
    int qq = unique(b + 1, b + all_num + 1) - b - 1;
    for(int i = 1; i <= n; i++) {
        q[i].l = lower_bound(b + 1, b + qq + 1, q[i].x - q[i].rr) - b;
        q[i].r = lower_bound(b + 1, b + qq + 1, q[i].x + q[i].rr) - b;
        q[i].x = lower_bound(b + 1, b + qq + 1, q[i].x) - b;
    }
    sort(q + 1, q + n + 1, [](Operation &a, Operation &b){
        return a.rr > b.rr;
    });
    CDQ(1, n);
    printf("%lld\n", ans);
    return 0;
}
posted @ 2021-02-02 11:10  Emcikem  阅读(82)  评论(0编辑  收藏  举报