2018.10.01【POJ2318】TOYS(二分查找)(叉积性质)


传送门


解析:

由于隔板输入是按照从左到右的顺序,所以我们可以每次二分查找这个物品落在那个隔板的区间。而问题就在于怎么二分查找。

思路:

这是计算几何中,最经典的叉积的应用。
关于叉积导面积的证明,请自行寻找资料,这里不再赘述,但提供几个方向。

1.三角形行列式面积公式。
2.投影。

那么这里我们每二分一条线段,计算其两个端点与询问的点围成的三角形的有向面积。从而判断三角形在哪个方向。


代码:

#include<iostream> #include<cstdio> #include<cctype> #include<cmath> #include<algorithm> using namespace std; #define ll long long #define re register #define gc getchar #define pc putchar #define cs const inline int getint(){ re int num; re char c; re bool f=0; while(!isdigit(c=gc()))f^=c=='-';num=c^48; while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48); return f?-num:num; } inline double getdb(){ re double x=0.0,y=1.0; re char c; re bool f=0; while(!isdigit(c=gc()))f^=c=='-';x=c^48; while(isdigit(c=gc()))x=(x*10)+(c^48); if(c!='.')return f?-x:x; while(isdigit(c=gc()))x+=(y/=10)*(c^48); return f?-x:x; } cs int N=5008; cs double eps=1e-6; struct Point{ double x,y; Point(double _x=0,double _y=0):x(_x),y(_y){} Point operator+(cs Point &b)cs{return Point(x+b.x,y+b.y);} Point operator-(cs Point &b)cs{return Point(x-b.x,y-b.y);} Point operator*(cs double &b)cs{return Point(x*b,y*b);} double operator*(cs Point &b)cs{return x*b.y-y*b.x;} double dot()cs{return x*x+y*y;} friend double dot(cs Point &a,cs Point &b){return a.x*b.x+a.y*b.y;} friend double cross(cs Point &a,cs Point &b){return a.x*b.y-a.y*b.x;} }O; inline double dist(cs Point &a){ return sqrt(a.dot()); } inline double dist(cs Point &a,cs Point &b){ return sqrt((a-b).dot()); } inline bool cmp(cs Point &a,cs Point &b){ return fabs(a.x-b.x)<eps?a.y<b.y:a.x<b.x; } struct Line{ Point p1,p2; Line(){} Line(Point _1,Point _2):p1(_1),p2(_2){} }line[N]; int n,ans[N],m; double x_1,y_1,x_2,y_2; signed main(){ while(n=getint(),n){ m=getint(); x_1=getint(); y_1=getint(); x_2=getint(); y_2=getint(); line[0].p1=Point(x_1,y_1); line[0].p2=Point(x_1,y_2); line[n+1].p1=Point(x_2,y_1); line[n+1].p2=Point(x_2,y_2); for(int re i=1;i<=n;++i){ x_1=getint(),x_2=getint(); line[i].p1=Point(x_1,y_1); line[i].p2=Point(x_2,y_2); } for(int re i=1;i<=m;++i){ Point c; c.x=getint(); c.y=getint(); int l=0,r=n; while(l<=r){ int mid=(l+r)>>1; if(cross(line[mid].p1-c,line[mid].p2-c)<0)r=mid-1; else l=mid+1; } ++ans[l-1]; } for(int re i=0;i<=n;++i)cout<<i<<": "<<ans[i]<<endl,ans[i]=0; cout<<endl; } return 0; } 
关注微信公众号

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com