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小于
备注:给的数据是从大到小排列,因为一开始我的思路是从小到大,为了偷懒,我把读取倒过来了,所以算结果那块会有点乱
#include<stdio.h>
#include<string.h>
///结构体,二维的二分,暴力不能过,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;///还回的是这个值的最小小标
}
mydouble x[100005];
int main()
{
    int n,m,i,j;
    mydouble a,b;
    long long c,d,e;long long sum;
    while(~scanf("%d%d",&n,&m))
    {
        for(i=n-1; i!=-1; i--)
        {
            scanf("%lf%lf",&x[i].x,&x[i].y);
        }
        for(i=0; i<m; i++)
        {
            scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
            sum=0;
            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);
        }
    }
}

 

 
posted @ 2017-12-28 13:17  moxin0509  阅读(544)  评论(0编辑  收藏  举报