平衡树维护动态凸包

codeforces70D

有两种操作, 1 x y   将(x,y)加入当前的点集合中。 2 x y  询问(x,y)是否在当前点集形成的凸包内。

 

即我们要动态的维护凸包,将凸包分为上凸包和下凸包,然后将上凸包关于x轴对称一下, 那么只要维护两个下凸包。

考虑用平衡树(为了让x有序)来维护凸包,插入一个点时,判断是否在下凸包的下方,如果是则插入且不断往两边删点,直到所有的点都满足凸包的定义为止。

如下图,插入点p5时,不断判断p5两边的点是否满足凸包的定义。

明显p2不满足。所有新的凸包是由点p1,p5,p3,p4组成。

 

平衡树维护动态凸包_第1张图片

 

代码里面要注意的是就是如果下凸包里面最左边或者最右边有点 (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 }
View Code

 

你可能感兴趣的:(平衡树维护动态凸包)