传送门
很有限制的一道题
对于任意机器人,存在一个初始位置点和一个观测半径以及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
", ans);
return 0;
}