1. 程式人生 > >CodeForces - 1046A AI robots(動態開點線段樹)

CodeForces - 1046A AI robots(動態開點線段樹)

A. AI robots

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

In the last mission, MDCS has successfully shipped NN 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 (xixi), radius of sight (riri) and IQ (qiqi).

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][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 KK.

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)N(1≤N≤105) and K(0≤K≤20)K(0≤K≤20).

Next NN lines contain three numbers each xi,ri,qi(0≤xi,ri,qi≤109)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

input

Copy

3 2
3 6 1
7 3 10
10 5 8

output

Copy

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.

 

題意:二維空間互相覆蓋的點有多少對。

 

解題思路:這是一個經典問題,先考慮一維的情況,直接掃描線即可。詳見官方題解。這裡提供另外一種思路,就是按照R排序,然後從大到小列舉,如果小的能看見大的,那麼大的肯定也能看見小的。所以直接線段樹查詢即可。這裡引入了 二維,由於第二位較小,直接暴力即可。這裡一共要開 10^9 棵 範圍為 0~1e9的線段樹。所以要動態開點。實際上用到的點不多,所以完全可以開得下。因為是動態開點,所以離散化都省了。詳見程式碼。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=100005;
const ll MAXQ=1e9+7;

struct point{
    ll x,r,q;
}Q[MAXN];

bool cmp(point &a,point &b){
    return a.r>b.r;
}
map<ll,int> mp;

int tot=0;
int ls[MAXN*40];
int rs[MAXN*40];
int sum[MAXN*40];
void update(int L,ll l,ll r,int &rt){
    if(rt==0)
        rt=++tot;
    if(l==r){
        sum[rt]++;
        return;
    }
    ll m=(l+r)/2;
    if(L<=m)
        update(L,l,m,ls[rt]);
    else
        update(L,m+1,r,rs[rt]);
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}

int query(int L,int R,ll l,ll r,int rt){
    if(rt==0)
        return 0;
    if(L<=l&&r<=R)
        return sum[rt];
    ll m=(l+r)/2;
    int ans=0;
    if(L<=m)
        ans+=query(L,R,l,m,ls[rt]);
    if(R>m)
        ans+=query(L,R,m+1,r,rs[rt]);
    return ans;
}

int main()
{
    int N,K;
    scanf("%d%d",&N,&K);
    for(int i=0;i<N;i++)
        scanf("%lld%lld%lld",&Q[i].x,&Q[i].r,&Q[i].q);

    sort(Q,Q+N,cmp);//R排序
    ll ans=0;
    for(int i=0;i<N;i++)
    {
        for(ll j=Q[i].q-K;j<=Q[i].q+K;j++)//列舉第二維所有的線段樹
        {
            if(!mp[j])
                continue;
            ans=ans+query(max(0ll,Q[i].x-Q[i].r),min(MAXQ,Q[i].x+Q[i].r),0,MAXQ,mp[j]);//暴力查詢
        }
        update(Q[i].x,0,MAXQ,mp[Q[i].q]);//更新
    }
    cout<<ans<<endl;
    return 0;
}