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); } } }