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);*/