To_Heart—题解——CF762E

First of all

stO LH Orz

更好的体验?

题意

在一维坐标轴上分布了 \(n\) 个机器人,第个机器人的坐标是 \(x_i\)

\(i\) 个机器人的视野是 \(r_i\) 。也就是说,第 \(i\) 个机器人能看到 \([x_i-r_i,x_i+r_i]\) 范围内的所有其他机器人。

\(i\) 个机器人的智商是 \(f_i\) 如果有一对机器人可以互相看到,并且它们的智商相差不超过 \(k\) ,那么它们就可以互相交流。

你需要求出来有多少对机器人可以互相交流。

题解

\(i\) , \(j\) 满足 \(1\leq i \leq j \leq n\)

有两个显然的式子:

\[\begin{cases} |x_i-x_j|\leq \min(r_i,r_j) \\ |f_i-f_j|\leq k \end{cases} \]

我们先忽略掉第二个式子

然后发现第一个式子有 \(\min\) 操作,挺不好看的,考虑以 \(r\) 为关键字从大到小排序后,化简得:

\[|x_i-x_j|\leq r_j \]

发现绝对值也挺不好看的,所以去掉绝对值:

\[\begin{cases} x_i-x_j\leq r_j \\ x_j-x_i\leq r_j \end{cases} \]

转换得到:

\[x_i-r_i\leq x_j\leq x_i+r_i \]

所以答案就转换为了对于每一个 \(i\) ,满足 \(x_i-r_i\leq x_j\leq x_i+r_i\)\(j\) 的个数和,这个很好用线段树维护。

这时我们再来看看第二个式子:

\[|f_i-f_j|\leq k \]

同样可以转换为:

\[f_i-k\leq f_j \leq f_i+k \]

再看看 \(f\) 的范围为\(10^4\),所以我们直接开\(10^4\)个线段树,然后再分别维护每个线段树就行了。

代码

因为我们考试的时候f的数据范围较大,用了离散化,但是不影响过题

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll

int lsh[200005];
int len=0;

struct ss{
    int x,r,q;
}a[200005];
bool cmp(ss x,ss y){
    if(x.r==y.r)
        return x.x<y.x;
    return x.r>y.r;
}
int n,k;

struct zz{
    int l,r;
    int val;
};

int tot=0;
zz t[4000005];
int rt[200005];
int New_Node(){
    tot++;
    t[tot].l=t[tot].r=t[tot].val=0;
    return tot;
}    
struct Tree{
    #define lc t[p].l
    #define rc t[p].r
    void Push_up(int p){
        int now=0;
        if(lc)    now+=t[lc].val;
        if(rc)     now+=t[rc].val;
        t[p].val=now;
    }
    void Change_Tree(int p,int l,int r,int x){
        if(l==r){
            t[p].val++;
            return ;
        }
        int mid=(l+r)>>1;
        if(x<=mid){
            if(!lc)    lc=New_Node();
            Change_Tree(lc,l,mid,x);
        }
        else{
            if(!rc)    rc=New_Node();
            Change_Tree(rc,mid+1,r,x);
        }
        Push_up(p);
    }
    int Find_Tree(int p,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            return t[p].val;
        }
        int mid=(l+r)>>1;
        int now=0;
        if(L<=mid&&lc)
            now+=Find_Tree(lc,l,mid,L,R);
        if(mid+1<=R&&rc)
            now+=Find_Tree(rc,mid+1,r,L,R);
        return now;
    }
}T[200005];

signed main(){
    int Max=0,Min=0x3f3f3f3f;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        scanf("%lld%lld%lld",&a[i].x,&a[i].r,&a[i].q);
        lsh[++len]=a[i].q;
        Max=max(Max,a[i].x+a[i].r);
        Min=min(Min,a[i].x-a[i].r);
    }    
    sort(a+1,a+n+1,cmp);
    sort(lsh+1,lsh+len+1);
    len=unique(lsh+1,lsh+len+1)-(lsh+1);
    for(int i=1;i<=n;i++)
        rt[i]=New_Node();
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=a[i].q-k;j<=a[i].q+k;j++){
            int now=lower_bound(lsh+1,lsh+len+1,j)-lsh;
            if(lsh[now]!=j)
                continue;
            ans+=T[now].Find_Tree(rt[now],Min,Max,a[i].x-a[i].r,a[i].x+a[i].r);
        }
        int now=lower_bound(lsh+1,lsh+len+1,a[i].q)-lsh;
        T[now].Change_Tree(rt[now],Min,Max,a[i].x);
    }
    cout<<ans<<endl;
    return 0;
}

posted @ 2021-09-03 21:27  To_Heart  阅读(41)  评论(0编辑  收藏  举报