Gym - 101964E - Fishermen - (二分+区间更新)

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/sdau20163942/article/details/84198163

提交链接:http://codeforces.com/gym/101964/problem/E

题面链接:https://vj.e949.cn/d8a88a967901013f7b7fe74f87ec1001?v=1542096019

题意:有n条鱼,给出每条鱼的坐标(a_{i},b_{i}),有m个人每个人都在横轴上坐标为(x_{i},0),第i个人与第j条鱼的距离为|a_{j}-x_{i}|+b_{j},现在每个人都有一个长为l的鱼竿,问对每个人有多少鱼在自己的鱼竿范围之内。

(1\leq n,m\leq 2*1e5, 1\leq l\leq 1e9)(1\leq x_i,y_i, a_i\leq1e9)

解析:想到对于每条鱼求一个[L,R],表示在岸边[L,R]的坐标范围内能够到此鱼,这里由于区间很大,要进行一下离散化,区间更新时二分分别找到x_lx_r(直接使用lower_bound()函数也行),使得x_l是大于等于坐标L的最靠左的人,x_r是小于等于坐标R的最靠右的人。然后对[x_l,x_r]进行一个区间更新即可。

代码(296ms

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=2e5+50;

struct Fish
{
    ll x,y;
}f[MAXN];
struct People
{
    ll x,id;
    bool operator <(const People& obj)const
    {
        return x<obj.x;
    }
}p[MAXN];

ll n,m,l,ans[MAXN];
ll where[MAXN],tp[MAXN];//tp[]用于lower_bound

ll Find1(ll x)
{
    if(x>p[m].x) return -666;
    return ((lower_bound(tp+1,tp+m+1,x))-(tp));
}
ll Find2(ll x)
{
    if(x<p[1].x) return -666;
    return ((upper_bound(tp+1,tp+m+1,x))-(tp));
}

int main()
{
    ll L,R;
    scanf("%I64d%I64d%I64d",&n,&m,&l);
    for(ll i=1;i<=n;i++)
        scanf("%I64d%I64d",&f[i].x,&f[i].y);
    for(ll i=1;i<=m;i++)
    {
        scanf("%I64d",&p[i].x);
        p[i].id=i;
    }
    sort(p+1,p+1+m);
    for(ll i=1;i<=m;i++)
    {
        where[p[i].id]=i;
        tp[i]=p[i].x;
    }
    for(ll i=1;i<=n;i++)
    {
        if(f[i].y>l) continue;
        L=f[i].x-(l-f[i].y);
        R=f[i].x+(l-f[i].y);
        //cout<<i<<" "<<L<<" "<<R<<" ";

        L=Find1(L);
        if(L==-666) continue;
        R=Find2(R);
        if(R==-666) continue;
        R--;
        //cout<<L<<" "<<R<<endl;
        ans[L]++;
        ans[R+1]--;
    }
    for(ll i=1;i<=m;i++)
        ans[i]+=ans[i-1];

    for(ll i=1;i<=m;i++)
        printf("%I64d\n",ans[where[i]]);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdau20163942/article/details/84198163