Codeforces 1045 G AI robots —— CDQ求三维+左右区间的数量

In the last mission, MDCS has successfully shipped N AI robots to Mars. Before they start exploring, system initialization is required so they are arranged in a line. Every robot can be described with three numbers: position (xi), radius of sight (ri) and IQ (qi).

Since they are intelligent robots, some of them will talk if they see each other. Radius of sight is inclusive, so robot can see other all robots in range [xi−ri,xi+ri]. But they don’t walk to talk with anybody, but only with robots who have similar IQ. By similar IQ we mean that their absolute difference isn’t more than K.

Help us and calculate how many pairs of robots are going to talk with each other, so we can timely update their software and avoid any potential quarrel.

Input
The first line contains two integers, numbers N(1≤N≤105) and K(0≤K≤20).

Next N lines contain three numbers each xi,ri,qi(0≤xi,ri,qi≤109) — position, radius of sight and IQ of every robot respectively.

Output
Output contains only one number — solution to the problem.

Example
inputCopy
3 2
3 6 1
7 3 10
10 5 8
outputCopy
1
Note
The first robot can see the second, but not vice versa. The first robot can’t even see the third. The second and the third robot can see each other and their IQs don’t differ more than 2 so only one conversation will happen.

题意:

给你n个机器人的位置,信号范围,智商。两个机器人能交流的智商范围k,两个机器人能交流当且仅当他们的信号能够相互到达且智商差距不大于k。问你有多少对机器人能够交流。

题解:

好像带修主席树也能写来着?但是很明显CDQ更加简单,因为主席树代码太长且debug的平均时间过长,能不用主席树就不用吧。但是一开始并没有想到CDQ怎么排序,还是看别人的代码才知道还能这样:
首先我们按照信号范围从大到小排序,这样就能保证从mid+1到r这个区间的机器人,他们信号所能到达的位置的那些l到mid的机器人的信号一定能到达他们。然后就是按照智商CDQ,这样的话只需要用两个指针维护智商能够交流的范围即可。最后树状数组记录l到mid 的机器人他们的位置,查询的话就查第i个机器人信号到达范围即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
struct node
{
    ll x,R,q,l,r;
}ro[N],t;
ll num[N*3];
int lowbit(int x)
{
    return x&(-x);
}
void add(int x,int val)
{
    for(int i=x;i<N*3;i+=lowbit(i))
        num[i]+=val;
}
ll query(int x)
{
    ll ans=0;
    for(int i=x;i;i-=lowbit(i))
        ans+=num[i];
    return ans;
}
void clear(int x)
{
    for(int i=x;i<N*3;i+=lowbit(i))
        num[i]=0;
}
ll ans=0;
bool cmp1(node x,node y)
{
    return x.R>y.R;
}
bool cmp2(node x,node y)
{
    return x.q<y.q;
}
int n,all;
ll k;
void CDQ(int l,int r)
{
    if(l>=r)
        return ;
    int mid=l+r>>1;
    CDQ(l,mid),CDQ(mid+1,r);
    int p1,p2;
    p1=p2=l;
    for(int i=mid+1;i<=r;i++)
    {
        while(p2<=mid&&ro[p2].q<=ro[i].q+k)
            add(ro[p2++].x,1);
        while(p1<p2&&ro[p1].q<ro[i].q-k)
            add(ro[p1++].x,-1);
        ans+=(query(ro[i].r)-query(ro[i].l-1));
        if(ans<0)
            cout<<query(ro[i].r)<<" "<<query(ro[i].l-1)<<endl;
    }
    //cout<<l<<" "<<r<<" "<<ans<<endl;
    for(int i=p1;i<p2;i++)
        clear(ro[i].x);
    sort(ro+l,ro+r+1,cmp2);
}
ll pos[N*3];
int main()
{

    scanf("%d%lld",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld%lld",&ro[i].x,&ro[i].R,&ro[i].q),pos[++all]=ro[i].x-ro[i].R,pos[++all]=ro[i].x,pos[++all]=ro[i].x+ro[i].R;
    sort(pos+1,pos+1+all);
    all=unique(pos+1,pos+1+all)-pos-1;
    for(int i=1;i<=n;i++)
        ro[i].l=lower_bound(pos+1,pos+1+all,ro[i].x-ro[i].R)-pos,ro[i].r=lower_bound(pos+1,pos+1+all,ro[i].x+ro[i].R)-pos,ro[i].x=lower_bound(pos+1,pos+1+all,ro[i].x)-pos;
    sort(ro+1,ro+1+n,cmp1);
    CDQ(1,n);
    printf("%lld\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值