FJUT ACM 2367题 二分强化——浮点数序列查询

Problem Description

已知在二维空间中有n个点,p0,p1……pn-1

已按照x为第一优先级,y为第二优先级从大到小排好序;

即若 pi<pj

则pi.x<pj.x,或者pi.x==pj.x&&pi.y<pj.y

 

Input

只有一组数据
第一行是两个整数n,m分别代表点的个数和查询次数
接下来n行,每行有二个带三位小数的浮点数x,y代表一个点的坐标
再接下来m行,每行的有4个数字x1,y1,x2,y2代表p1,p2且p1>=p2

其中n,m<=100000;

任意0<=x,y<10^6;

 

Output

输出n个点所有小于等于p1且大于等于p2的点的下标之和

SampleInput
6 4
125.689 125.689
125.689 125.688
125.688 125.689
125.688 125.689
125.688 125.688
125.688 125.688
125.688 125.688 125.688 125.688
125.688 125.689 125.688 125.688
125.689 125.689 125.688 125.689
125.688 125.689 125.688 125.689
SampleOutput
9
14
6
5

该题很明显就是一个二分的题目,(ps:题目告诉你就是二分强化啊。。。)
该题要求的事寻找一个小于等于p1且大于等于p2的点的下标之和,就是说是寻找一个范围,在将范围的值累加起来,而在寻找的过程中采取遍历的话,其结果是必定超时的!
所以我们应该用二分去寻找两个下标,一个去寻找小于等于p1的下标,一个去寻找比p2大的下标,这时候我们很有可能写个for循环将p1与p2的值累加起来,但是这种操作会导致
凉凉(TLE),我们这个时候可以使用求和公式,因为从p1到p2必定是一个等差数列,且d=1;用等差数列求和公式求解就可以了!
而寻找的过程,是一个二维二分的过程,(其实还有一种黑科技,来至CWL学长,他说乘于一个数值,使其可以用一维来表示,然后就是一维的二分了)
其实二维二分并不难,在x相等的情况下讨论y就可以了
1.x相等的情况下,y大于或等于
2.x相等的情况下,y小于
3.x大于或等于
4.x小于
贴上核心代码:(cyh大佬说不要放全部代码,那我就放部分吧)
备注:给的数据是从大到小排列,因为一开始我的思路是从小到大,为了偷懒,我把读取倒过来了,所以算结果那块会有点乱
///结构体,二维的二分,暴力不能过,emmmmmm
typedef struct Mydouble
{
    double x;
    double y;
} mydouble;
long long Tmaxfind(double a,double b,int n, mydouble x[])
{
    int left,right,mid;
    left=-1;
    right=n;
    mid=(left+right)/2;
    while(left+1<right)
    {
        if(x[mid].x>a||(x[mid].x==a&&x[mid].y>b))
        {
            right=mid;
            mid=(right+left)/2;
            continue;
        }
        if(x[mid].x<a||(x[mid].x==a&&x[mid].y<=b))
        {
            left=mid;
            mid=(left+right)/2;
            continue;
        }
    }
    return right;///还回的是大一号的值的下标
}
long long Tminfind(double a,double b,int n, mydouble x[])
{
    int left,right,mid;
    left=-1;
    right=n;
    mid=(left+right)/2;
    while(left+1<right)
    {
        if(x[mid].x>a||(x[mid].x==a&&x[mid].y>=b))
        {
            right=mid;
            mid=(right+left)/2;
            continue;
        }
        if(x[mid].x<a||(x[mid].x==a&&x[mid].y<b))
        {
            left=mid;
            mid=(left+right)/2;
            continue;
        }
    }
    return right;///还回的是这个值的最小小标
}
/*
这一部分是求和的代码
d=Tmaxfind(a.x,a.y,n,x);
            e=Tminfind(b.x,b.y,n,x);
            //printf("大的值+1的下标=%d 小的值最小下标%d\n",d,e);
            sum=(((n-d-1)+(n-e))*(d-e))/2;
            /*for(e;e<d;e++)
            {
                sum+=(n-1-e);这里暴力超时
            }*/
            printf("%lld\n",sum);*/

  

 

转载于:https://www.cnblogs.com/qq136155330/p/8135189.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值