CodeForces 1045G AI robots(CDQ分治 + 树状数组 + 单调队列)

版权声明:本文为博主原创文章,转载请著名出处 http://blog.csdn.net/u013534123 https://blog.csdn.net/u013534123/article/details/83241568

大致题意:有很多个机器人,他们要相互交流有一些限制条件。首先是,两个人要相互能够能够看到;其次,两个人的智商的差不超过K。现在给出每个机器人的视力范围和他们的智商,现在问你总共有多少对机器人能够相互交流。

首先来看下总共有多少个限制条件。由于是要求双方都能够看到,所以显然是要按照视野半径去排序的。然后要求两个人的智商差要在一定的范围内的,所以也要按照智商去排序。另外还要跟自己的位置有关。根据这个,我们可以构造出分治的大致方法:首先按照半径去排序,半径大的在前面,因为这样如果后面的东西能够看到前面,那么前面的东西一定能看到后面,符合cdq分治前面更新后面的要求;然后分治的过程中归并排序按照智商的大小去排序,因为这样可以利用一些单调性,同时好确定智商差;最后就是用一个离散化的树状数组去维护每个位置的机器人数量。

前面和最后的都好说,关键是如何利用智商差去求能够相互看到的机器人的对数。这里我们用到了单调队列。由于是按照智商的大小来进行分治的。所以前一半和后一半已经是按照智商的大小排好序了的,所以说我们可以利用单调性。根据cdq分治的原则,前面一半去更新后面一半,所以我们考虑对于后一半的每个机器人,单独计算贡献。对于后一半的第i个机器人,我可以在前一半确定一个区间[j,k],在这个区间内的所有机器人与机器人i的智商差不超过K。把这个区间内的所有机器人添加到树状数组中,然后贡献就是机器人i视野范围内的机器人数目。然后再往后考虑后一半的其他机器人。由于前一半和后一半的智商是递减的,所以从i移动到i+1区间的移动只会单调往后移动,符合单调队列性质。这样前一半的每一个机器人只会进出队列各一次,对应加入和移出树状数组各一次。所以这个部分均摊的时间复杂度是O(NlogN)的,这个log来自树状数组。

如此我们就求出了合并的时候前面对后面产生的贡献。总的时间复杂度就是O(NlogNlogN)。具体见代码:

#include<bits/stdc++.h>
#define LL long long
#define N 100010

using namespace std;

struct node{int x,r,iq,L,R;} p[N],tmp[N];
int n,tot,K,x[N<<2],q[N]; LL ans=0;

struct BinaryIndexedTree
{
    int c[N<<2];

    inline void update(int x,int k)
    {
        x=min(x,tot);
        for(;x<=tot;x+=x&-x) c[x]+=k;
    }

    inline int getsum(int x)
    {
        int ans=0;
        for(;x>0;x-=x&-x) ans+=c[x];
        return ans;
    }

} BIT;

bool cmp1(node a,node b)
{
    return a.r>b.r;
}

bool cmp2(node a,node b)
{
    return a.iq>b.iq;
}

void cdq(int l,int r)
{
    if (l==r) return;
    int mid=(l+r)>>1;
    cdq(l,mid);
    cdq(mid+1,r);
    int h=0,t=0;
    for(int i=mid+1,j=l;i<=r;i++)
    {
        while(j<=mid&&p[j].iq-p[i].iq>K) j++;
        while(j<=mid&&abs(p[j].iq-p[i].iq)<=K)
        {
            BIT.update(p[j].x,1);
            q[t++]=j++;
        }
        while(h<t&&abs(p[q[h]].iq-p[i].iq)>K)
        {
            BIT.update(p[q[h]].x,-1);
            h++;
        }
        ans+=BIT.getsum(p[i].R)-BIT.getsum(p[i].L-1);
    }
    for(;h<t;h++) BIT.update(p[q[h]].x,-1);
    inplace_merge(p+l,p+mid+1,p+r+1,cmp2);
}

int main()
{
    scanf("%d%d",&n,&K);
    for(int i=1;i<=n;i++)
    {
        int X,Y,Z;
        scanf("%d%d%d",&X,&Y,&Z);
        p[i]=node{X,Y,Z,0,0};
        x[++tot]=X; x[++tot]=X-Y; x[++tot]=X+Y;
    }
    sort(x+1,x+tot+1);
    tot=unique(x+1,x+tot+1)-x-1;
    for(int i=1;i<=n;i++)
    {
        p[i].L=lower_bound(x+1,x+tot+1,p[i].x-p[i].r)-x;
        p[i].R=lower_bound(x+1,x+tot+1,p[i].x+p[i].r)-x;
        p[i].x=lower_bound(x+1,x+tot+1,p[i].x)-x;
    }
    sort(p+1,p+n+1,cmp1);
    cdq(1,n);
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/83241568