平衡树维护动态凸包
codeforces70D
有两种操作, 1 x y 将(x,y)加入当前的点集合中。 2 x y 询问(x,y)是否在当前点集形成的凸包内。
即我们要动态的维护凸包,将凸包分为上凸包和下凸包,然后将上凸包关于x轴对称一下, 那么只要维护两个下凸包。
考虑用平衡树(为了让x有序)来维护凸包,插入一个点时,判断是否在下凸包的下方,如果是则插入且不断往两边删点,直到所有的点都满足凸包的定义为止。
如下图,插入点p5时,不断判断p5两边的点是否满足凸包的定义。
明显p2不满足。所有新的凸包是由点p1,p5,p3,p4组成。
代码里面要注意的是就是如果下凸包里面最左边或者最右边有点 (1,0), 那么新加入的点如果是(1,y),y>0, 那么该点不用加入下凸包,因为该点会加入上凸包的。
1 #include <iostream> 2 #include <map> 3 #include <vector> 4 #include <stdio.h> 5 using namespace std; 6 typedef struct Point{ 7 double x,y; 8 Point(){} 9 Point(double x, double y):x(x),y(y){} 10 }Vector; 11 Vector operator+(const Vector &a, const Vector &b){ 12 return Vector(a.x+b.x, a.y+b.y); 13 } 14 Vector operator-(const Vector &a, const Vector &b){ 15 return Vector(a.x-b.x,a.y-b.y); 16 } 17 double Cross(const Vector &a, const Vector &b){ 18 return a.x * b.y - b.x * a.y; 19 } 20 21 map<int,int> convex[2]; 22 map<int,int>::iterator l,r,l2,r2; 23 bool isIn(map<int,int>&ma, int x, int y){ 24 if(ma.size()==0) return false; 25 if(ma.find(x)!=ma.end()) return y >= ma[x]; 26 if(x < (ma.begin()->first) || ((--ma.end())->first) < x) return false; 27 l = r = ma.lower_bound(x); 28 l--; 29 Point L(l->first,l->second); 30 Point R(r->first,r->second); 31 Point now(x,y); 32 return Cross(R-L,now-L) >= 0; 33 } 34 void insert(map<int,int> &ma, int x, int y){ 35 if(isIn(ma,x,y))return; 36 ma[x] = y; 37 r = ma.upper_bound(x); 38 39 if(r!=ma.end()){ 40 r2 = r; 41 r2++; 42 while(r2!=ma.end()){ 43 Point R(r->first,r->second); 44 Point R2(r2->first,r2->second); 45 Point now(x,y); 46 if(Cross(R-now,R2-now)<0){ 47 ma.erase(r); 48 r = r2; 49 r2++; 50 } 51 else 52 break; 53 } 54 55 } 56 l = ma.lower_bound(x); 57 if(l==ma.begin()){ 58 return; 59 } 60 l--; 61 if(l==ma.begin()) 62 return; 63 l2 = l; 64 l2--; 65 while(l!=ma.begin()){ 66 Point L(l->first,l->second); 67 Point L2(l2->first,l2->second); 68 Point now(x,y); 69 if(Cross(L2-now,L-now)<0){ 70 ma.erase(l); 71 l = l2; 72 l2--; 73 } 74 else{ 75 break; 76 } 77 } 78 79 } 80 81 int main() 82 { 83 int n; 84 scanf("%d",&n); 85 for(int i=1;i<=n;++i){ 86 int x,y,type; 87 scanf("%d%d%d",&type,&x,&y); 88 if(type==1){ 89 insert(convex[0],x,y); 90 insert(convex[1],x,-y);//x轴对称一次,把上凸包变成下凸包 91 //printf("%d %d\n",convex[0].size(),convex[1].size()); 92 } 93 else{ 94 //在下凸包的上方 95 bool ans1 = isIn(convex[0],x,y); 96 //在上凸包的下方 97 bool ans2 = isIn(convex[1],x,-y); 98 if(ans1&&ans2){ 99 puts("YES"); 100 } 101 else{ 102 puts("NO"); 103 } 104 } 105 106 } 107 return 0; 108 }