第一次写水平序凸包,感觉跟极角序凸包差不多
凸包的删除看上去不太可做,但我们发现这题没有强制在线,所以我们离线统计答案
离线之后把操作反序,删除就变为插入了
用平衡树维护凸包,每插入一个点,就不停删除它左右两边不满足凸包性质的点
每个点只会被插入删除各一次,不会超时
1 #include<stdio.h> 2 #include<math.h> 3 #include<set> 4 using namespace std; 5 const double eps=1e-8; 6 struct point{ 7 double x,y; 8 point(double a=.0,double b=.0){ 9 x=a; 10 y=b; 11 } 12 }c[100010],cc; 13 bool operator<(point a,point b){ 14 if(a.x==b.x)return a.y<b.y; 15 return a.x<b.x; 16 } 17 set<point>s,tmp; 18 set<point>::iterator ita,itb,it; 19 int ask[200010]; 20 double ans,tans[200010]; 21 double dist(point a,point b){ 22 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 23 } 24 double cross(double x1,double y1,double x2,double y2){ 25 return x1*y2-y1*x2; 26 } 27 void insert(point x){ 28 ita=s.lower_bound(x); 29 itb=ita; 30 ita--; 31 if(cross(x.x-ita->x,x.y-ita->y,itb->x-x.x,itb->y-x.y)>=-eps)return; 32 ans-=dist(*ita,*itb); 33 while(ita!=s.begin()){ 34 it=ita; 35 it--; 36 if(cross(ita->x-it->x,ita->y-it->y,x.x-ita->x,x.y-ita->y)>=-eps){ 37 ans-=dist(*ita,*it); 38 cc=*it; 39 s.erase(ita); 40 ita=s.find(cc); 41 }else 42 break; 43 } 44 it=itb; 45 it++; 46 while(it!=s.end()){ 47 if(cross(itb->x-x.x,itb->y-x.y,it->x-itb->x,it->y-itb->y)>=-eps){ 48 ans-=dist(*it,*itb); 49 cc=*it; 50 s.erase(itb); 51 itb=s.find(cc); 52 }else 53 break; 54 it=itb; 55 it++; 56 } 57 ans+=dist(x,*ita)+dist(x,*itb); 58 s.insert(x); 59 } 60 int main(){ 61 int i,a,b,m,q; 62 scanf("%d%d%d",&i,&a,&b); 63 ans=dist(point(),point(a,b))+dist(point(i,0),point(a,b)); 64 s.insert(point()); 65 s.insert(point(i,0)); 66 s.insert(point(a,b)); 67 scanf("%d",&m); 68 for(i=1;i<=m;i++){ 69 scanf("%lf%lf",&c[i].x,&c[i].y); 70 tmp.insert(c[i]); 71 } 72 scanf("%d",&q); 73 for(i=1;i<=q;i++){ 74 scanf("%d",&a); 75 if(a==1){ 76 scanf("%d",ask+i); 77 tmp.erase(c[ask[i]]); 78 } 79 } 80 for(it=tmp.begin();it!=tmp.end();it++)insert(*it); 81 for(i=q;i>0;i--){ 82 if(ask[i]) 83 insert(c[ask[i]]); 84 else 85 tans[i]=ans; 86 } 87 for(i=1;i<=q;i++){ 88 if(ask[i]==0)printf("%.2lf\n",tans[i]); 89 } 90 }
时间: 2024-07-30 14:24:56