题目链接:Codeforces - AI robots
稍微想一下,应该能想到,如果我们按照半径r排序,那么我们就只需要统计我们能到达的点,然后就不用考虑相互到达的问题了。
然后因为k很小,所以我们暴力对每一个IQ建立权值线段树,然后依次查找即可。
用CDQ分治,也能解决。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10,M=N*60;
int n,k,m,up=1e9; unordered_map<int,int> mp;
struct node{int x,r,q;}t[N]; long long res;
int rt[N],sum[M],lc[M],rc[M],cnt;
vector<int> v;
inline int get(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
int cmp(node a,node b){return a.r>b.r;}
void change(int &p,int l,int r,int x){
if(!p) p=++cnt;
if(l==r){sum[p]++; return;}
int mid=l+r>>1;
if(x<=mid) change(lc[p],l,mid,x);
else change(rc[p],mid+1,r,x);
sum[p]=sum[lc[p]]+sum[rc[p]];
}
int ask(int p,int l,int r,int ql,int qr){
if(!p) return 0;
if(l==ql&&r==qr) return sum[p];
int mid=l+r>>1;
if(qr<=mid) return ask(lc[p],l,mid,ql,qr);
else if(ql>mid) return ask(rc[p],mid+1,r,ql,qr);
else return ask(lc[p],l,mid,ql,mid)+ask(rc[p],mid+1,r,mid+1,qr);
}
signed main(){
cin>>n>>k;
for(int i=1;i<=n;i++)
scanf("%d %d %d",&t[i].x,&t[i].r,&t[i].q),v.push_back(t[i].q);
sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end());
sort(t+1,t+1+n,cmp);
for(int i=0;i<v.size();i++) mp[v[i]]=1;
for(int i=1;i<=n;i++){
for(int j=t[i].q-k;j<=t[i].q+k;j++){
if(!mp[j]) continue;
res+=ask(rt[get(j)],0,up,max(0,t[i].x-t[i].r),min(up,t[i].x+t[i].r));
}
change(rt[get(t[i].q)],0,up,t[i].x);
}
cout<<res;
return 0;
}