poj 2318叉積解点と直線の関係


点の位置を判断するには、二分法による判断と境界線の相対位置、最終的に点の所在ブロックを決定し、配列、点の位置を判断する際にフォークで方向のある面積を積算する.
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
//#include <cmath>
#define MAX 5007

using namespace std;

struct Point 
{
    int x , y;
    Point ( ) : x(0) , y(0) {}
    Point ( int a , int b ) : x(a),y(b){}
}p;

struct Line 
{
    Point up , down;
}l[MAX];

int det ( Point a  , Point b )
{
    return a.x * b.y - a.y*b.x;
}

int n,m,x1,y1,x2,y2,u,d;

int  id ( Point p )
{
    if ( det ( Point ( p.x - l[n].down.x , p.y - l[n].down.y ) ,
         Point ( l[n].up.x - p.x , l[n].up.y - p.y))
            > 0 ) return n+1;
    int left = 1 , right = n , mid;
    while ( left != right )
    {
        mid = left + right >> 1;
       // cout << mid << endl;
        //cout << det ( Point ( p.x-l[mid].down.x , p.y-l[mid].down.y ) ,
           //   Point ( l[n].up.x - p.x , l[mid].up.y - p.y)) << endl;
        if ( det ( Point ( p.x-l[mid].down.x , p.y-l[mid].down.y ) ,
             Point ( l[mid].up.x - p.x , l[mid].up.y - p.y ))
                > 0 )  left  = mid + 1;
        else right = mid;
    }
    return left; 
}

int main ( )
{
    int ans [MAX];
    while ( ~scanf("%d" , &n ),n )
    {
        scanf ( "%d%d%d%d%d" , &m , &x1 , &y1 , &x2 , &y2 );
        memset ( ans , 0 , sizeof ( ans ) );
        for ( int i = 1 ; i <= n ; i++ )
        {
            scanf ( "%d%d" , &l[i].up.x , &l[i].down.x );
            l[i].up.y = y1 , l[i].down.y =y2;
        }
        for ( int i = 1 ; i <= m ; i++ )
        {
            scanf ( "%d%d" , &p.x , &p.y );
            ans[id( p )]++;
        }
        for ( int i = 1 ; i <= n+1 ; i++ )
            printf ( "%d: %d
" , i-1 , ans[i] ); printf ( "
" ); } }