CF1045G AI robots(动态开点线段树)

题意

火星上有$N$个机器人排成一行,第$i$个机器人的位置为$x_{i}$,视野为$r_{i}$,智商为$q_{i}$。我们认为第$i$个机器人可以看到的位置是$[x_{i}-r_{i},x_{i}+r_{i}]$。如果一对机器人相互可以看到,且它们的智商$q_{i}$的差距不大于$K$,那么它们会开始聊天。 为了防止它们吵起来,请计算有多少对机器人可能会聊天。

题解

先膜一下大佬->这里

我们先按视野降序排序,这样一个一个考虑,如果后面的能看到前面,那前面的也肯定能看到后面

这样,就是对于每一个机器人,在他前面有几个智商在$[q-k,q+k]$,位置在$[x-r,x+r]$

那么把这个东西看做一个矩形覆盖就可以了

然后因为智商这一维维数很小,我们可以对每一个智商开一个动态开点线段树,然后一个一个扫过去统计答案就可以了

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<map>
 6 #define ll long long
 7 using namespace std;
 8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 9 char buf[1<<21],*p1=buf,*p2=buf;
10 inline int read(){
11     #define num ch-'0'
12     char ch;bool flag=0;int res;
13     while(!isdigit(ch=getc()))
14     (ch=='-')&&(flag=true);
15     for(res=num;isdigit(ch=getc());res=res*10+num);
16     (flag)&&(res=-res);
17     #undef num
18     return res;
19 }
20 const int N=1e5+5;
21 int n,k,m,b[N*3];ll res;
22 map<int,int> rt;int L[N<<5],R[N<<5],sum[N<<5],cnt=0;
23 void update(int p,int l,int r,int x){
24     ++sum[p];if(l==r) return;
25     int mid=(l+r)>>1;
26     if(x<=mid) update(L[p]=L[p]?L[p]:++cnt,l,mid,x);
27     else update(R[p]=R[p]?R[p]:++cnt,mid+1,r,x);
28 }
29 int query(int p,int l,int r,int ql,int qr){
30     if(ql<=l&&qr>=r||p==0) return sum[p];
31     int mid=(l+r)>>1,res=0;
32     if(ql<=mid) res+=query(L[p],l,mid,ql,qr);
33     if(qr>mid) res+=query(R[p],mid+1,r,ql,qr);
34     return res;
35 }
36 inline void ins(int q,int x){
37     if(rt.count(q)==0) rt[q]=++cnt;
38     update(rt[q],1,m,x);
39 }
40 inline int get(int q,int ql,int qr){
41     if(rt.count(q)==0) return 0;
42     return query(rt[q],1,m,ql,qr);
43 }
44 struct node{
45     int x,r,q;
46     node(){}
47     node(int x,int r,int q):x(x),r(r),q(q){}
48     inline bool operator <(const node &b)const
49     {return r>b.r;}
50 }a[N];
51 int main(){
52 //    freopen("testdata.in","r",stdin);
53     n=read(),k=read();
54     for(int i=1;i<=n;++i){
55         int x=read(),r=read(),q=read();
56         a[i]=node(x,r,q);
57         b[++m]=x,b[++m]=x-r,b[++m]=x+r;
58     }
59     sort(b+1,b+1+m),m=unique(b+1,b+1+m)-b-1;
60     sort(a+1,a+1+n);
61     for(int i=1;i<=n;++i){
62         int l=lower_bound(b+1,b+1+m,a[i].x-a[i].r)-b;
63         int r=lower_bound(b+1,b+1+m,a[i].x+a[i].r)-b;
64         int x=lower_bound(b+1,b+1+m,a[i].x)-b;
65         for(int j=a[i].q-k;j<=a[i].q+k;++j)
66         res+=get(j,l,r);
67         ins(a[i].q,x);
68     }
69     printf("%lld\n",res);
70     return 0;
71 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9749892.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值