POJ 2318 TOYS | 二分+判断点在多边形内
题意:
给一个矩形的区域(左上角为(x1,y1) 右下角为(x2,y2)),给出n对(u,v)表示(u,y1) 和 (v,y2)构成线段将矩形切割
这样构成了n+1个多边形,再给出m个点,问每个多边形内有多少个点.
读入为n,m,x1,y1,x2,y2
n个数对(u,v),m个数对(x,y) (n,m<=5000)
题解:
很暴力的想法是对于每个点,枚举每个多边形进行检查.
但是多组数据就很江
考虑一下判断点在多边形内的射线法可知
枚举一个多边形的时候就可以知道点在多边形的左边还是右边
这样我们对每个点二分一下他属于那个多边形,依靠上述性质就可以在nlogn时间内做完
#include<cstdio> #include<algorithm> #include<cstring> typedef long long ll; #define N 5010 using namespace std; int n,m,x1,x2,y1,y2,up[N],down[N],cnt[N],t; struct point { int x,y; point (){} ; point (int _x,int _y) : x(_x),y(_y) {}; bool operator < (const point &rhs) const { if (x==rhs.x) return y<rhs.y; return x<rhs.x; } inline int operator * (const point &rhs) const { return x*rhs.y-y*rhs.x; } inline point operator - (const point &rhs) const { return point(x-rhs.x,y-rhs.y); } friend inline int dot (const point &lhs,const point &rhs) { return lhs.x*rhs.x+lhs.y*rhs.y; } }toy[N]; bool isinline (const point &p1,const point &p2,const point &p3) { int det=(p1-p3)*(p2-p3); if (det!=0) return 0; int Dot=dot(p1-p3,p2-p3); return Dot<=0; } struct polygon { point p[10]; int inner (const point &pp) { int cnt=0; for (int i=1;i<=4;i++) { if (isinline(p[i],p[i+1],pp)) return 1; int d1=p[i].y-pp.y,d2=p[i+1].y-pp.y; int del=(p[i]-pp)*(p[i+1]-pp); if ( (del>=0 && d1>=0 && d2<0) || (del<=0 && d1<0 && d2>=0) ) cnt++; } return cnt; } }pol[N]; void solve() { sort(toy+1,toy+1+m); memset(cnt,0,sizeof(cnt)); for (int i=0;i<=n;i++) { pol[i].p[1]=pol[i].p[5]=point(up[i],y1); pol[i].p[4]=point(down[i],y2); pol[i].p[3]=point(down[i+1],y2); pol[i].p[2]=point(up[i+1],y1); } for (int i=1;i<=m;i++) { int l=0,r=n,mid; while (l<=r) { mid=l+r>>1; int res=pol[mid].inner(toy[i]); if (res&1) { cnt[mid]++; break; } if (res>0) l=mid+1; else r=mid; } } } int main() { while (scanf("%d",&n),n) { if (++t!=1) puts(""); scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2); for (int i=1;i<=n;i++) scanf("%d%d",&up[i],&down[i]); for (int i=1,x,y;i<=m;i++) { scanf("%d%d",&x,&y); toy[i]=point(x,y); } up[0]=down[0]=x1,up[n+1]=down[n+1]=x2; solve(); for (int i=0;i<=n;i++) printf("%d: %d\n",i,cnt[i]); } return 0; }