UVALive 7281 Saint John Festival (凸包+O(logn)判断点在凸多边形内)

时间:2023-03-09 01:00:39
UVALive 7281	Saint John Festival (凸包+O(logn)判断点在凸多边形内)

Saint John Festival

题目链接:

http://acm.hust.edu.cn/vjudge/contest/127406#problem/J

Description


```
Porto’s Festa de São João is one of Europe’s liveliest street
festivals. Its peak is the night of 23rd to 24th of June, with
dancing parties from Ribeira to Foz all night long.
Time to celebrate, with friends, relatives, neighbours or
simply with other people in streets, armed with colored plastic
hammers, huge garlic flowers or a bunch of lemongrass
to gently greet passers-by. Fireworks, grilled sardines, barbecues,
bonfires, potted basil plants (manjericos) and the
sky covered by incandescent sky *s (balões de S.João)
launched from every corner make this party unique.
The sky *s are made of thin paper and cannot be
released until they are filled in with hot air. Sometimes they
burn out still on ground or on the way up, if a sudden gust
of wind catches them. For this reason, the successful launchers
usually follow the movement of their sky *s, with a
mixture of anxiety and joy, for as long as they can distinguish
them in the sky.
We are not aware of any attempt to achieve a Guinness
record of sky *s launched simultaneously (it could be
dreadful night for firemen if there were).
Can you imagine, thousands of people preparing their sky
*s for release at the city park, within a region of larger ones that will be launched simultaneously?
The large sky *s can be used to identify their positions in the sky afterwards, in order to
count the surviving ones at an observation instant.
Given the positions of the large sky *s and the positions of the small ones, determine the
number of small sky *s that are in the interior or on the boundary of some triangle defined by
any three of the large ones.
```

Input


The input file contains several test cases, each of them as described below.
The first line has an integer L that defines the number of the large sky *s at the observation
instant. Each of the following L lines contains a pair of integers separated by a space that gives the
coordinates (x, y) of a large sky *. After that, there is a line with an integer S that defines the
number of small sky *s and S lines, each defining the position of a small sky *. The height
is irrelevant for us. All the given points are distinct and there are at least three points representing
large sky *s that are not collinear.

Output


For each test case, the output has a single line with the number of small sky *s that are in the
interior or on the boundary of some triangle defined by any three of the large sky *s.
Constraints:
3 ≤ L ≤ 10 000 Number of large sky *s.
1 ≤ S ≤ 50 000 Number of small sky *s.
0 ≤ x, y ≤ 2
30 Bounds for coordinates.
Note: The picture on the right illustrates the sample input below

Sample Input


8
3 4
2 8
5 4
1 8
4 7
3 10
11 2
7 3
6
5 12
3 7
3 3
4 5
0 4
2 6

Sample Output


3


##题意:

在平面上给出若干个"大点"和"小点".
求有多少个小点满足:在任一由三个大点组成的三角形的内部或边界上.


##题解:

看图很容易看出要求一个凸包(证明也很容易).
然后依次判断各点是否在凸包内或边界上.
需要注意的是:
用longlong代替double参与运算,避免精度误差.
由于数据规模的限制,判断点是否在凸多边形内时要用O(logn)的算法. 以下代码用了二分法.


##代码:
``` cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define eps 1e-8
#define double LL
#define maxn 101000
#define mod 100000007
#define inf 0x3f3f3f3f
#define mid(a,b) ((a+b)>>1)
#define IN freopen("in.txt","r",stdin);
using namespace std;

struct Point{

double x,y;

Point(){}

Point(double tx,double ty) {x=tx;y=ty;}

// bool operator<(const Point& b)const

// {

// if(x==b.x) return y<b.y;

// return x<b.x;

// }

};

int sign(double x)

{

//if(fabs(x)<eps) return 0;

if(x == 0) return 0;

return x<0? -1:1;

}

double dmul(Point p0,Point p1,Point p2)

{return (p1.x-p0.x)(p2.x-p0.x)+(p1.y-p0.y)(p2.y-p0.y);}

/x>0逆时针 x<0顺时针 x=0三点共线 考虑精度/

double xmul(Point p0,Point p1,Point p2)

{return (p1.x-p0.x)(p2.y-p0.y)-(p2.x-p0.x)(p1.y-p0.y);}

/求两点间距离/

double Distance(Point p1,Point p2)

{

return sqrt((p1.x-p2.x)(p1.x-p2.x)+(p1.y-p2.y)(p1.y-p2.y));

}

int n,m;

Point points[11000];

int _stack[11000],top; /_stack保存凸包构成点,逆时针/

int cmp_with_polar(Point p1,Point p2)

{

double tmp=xmul(points[0],p1,p2);

if(sign(tmp)>0) return 1;

else if(sign(tmp)==0&&sign(Distance(points[0],p1)-Distance(points[0],p2))<0)

return 1;

else return 0;

}

void polar_sort(int n)

{

int pos=0;

Point p0;

p0.x=points[0].x;p0.y=points[0].y;

for(int i=1;i<n;i++){
if(sign(p0.y-points[i].y)>0||(sign(p0.y-points[i].y)==0&&sign(p0.x-points[i].x)>0)){
p0.x=points[i].x;
p0.y=points[i].y;
pos=i;
}
}
points[pos]=points[0];
points[0]=p0; sort(points+1,points+n,cmp_with_polar);

}

void ConvexHull_Graham(int n) /最终凸包点为_stack[0]~_stack[top-1],共top个/

{

polar_sort(n);

top=0;

for(int i=0;i<n;i++){

while(top>1&&sign(xmul(points[_stack[top-2]],points[_stack[top-1]],points[i]))<=0) top--;

_stack[top++]=i;

}

}

double cross(Point p0, Point p1, Point p2)

{

return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);

}

/二分法判断点是否在凸多边形内(或边界上)/

bool is_in(int index[], int n, Point p) {

int l=1, r=n-2,mid;

while(l<=r) {

mid = (l+r) >> 1;

double a1 = xmul(points[index[0]], points[index[mid]], p);

double a2 = xmul(points[index[0]], points[index[mid+1]], p);

if(sign(a1)>=0 && sign(a2)<=0) {

if(sign(xmul(points[index[mid]], points[index[mid+1]], p)) >= 0) return 1;

return 0;

} else if(sign(a1) < 0) {

r = mid -1;

} else {

l = mid+1;

}

}

return 0;

}

int main(int argc, char const *argv[])

{

//IN;

int n, m;
while(scanf("%d", &n) != EOF)
{
for(int i=0; i<n; i++) {
scanf("%I64d %I64d", &points[i].x,&points[i].y);
}
ConvexHull_Graham(n); //for(int i=0; i<top; i++)
// printf("%I64d %I64d\n", points[_stack[i]].x, points[_stack[i]].y); scanf("%d", &m);
int ans = 0;
while(m--) {
Point cur;
scanf("%I64d %I64d", &cur.x,&cur.y);
if(is_in(_stack, top, cur)) ans++;
} printf("%d\n", ans);
} return 0;

}