题目大意:给你m+3个点,有q个操作,每次要么询问当前点集构所构成的上凸壳总长度,要么在当前点集中删除一个点。
这题是吼题啊!!!
刚开始想着如何正常地做,考虑过用线段树维护一个区间内的凸包,发现并不行,要另请高明。
后来发现,这题并没有强制在线要求,我们不妨将所有的询问反过来处理。首先将从头到尾都没有被删除的点加入该凸包,然后将询问倒序处理,将原先的删点操作改为加点操作,随后动态维护该凸包并维护上凸壳总长度,需输出的答案压入一个栈中,最后逐个弹出输出即可。
至于如何动态维护凸包。本题有一个很特殊的条件:所有点坐标的x,y值均大于0,且必有一个点坐标为(0,0)。故我们可以用一个set维护当前在凸包上的点,当需要加入一个点k时,借助lower_bound找到与该点相邻夹角的两个点,直接进行维护即可。实现细节较为复杂,强烈建议先工整地将维护方法写在草稿纸上!!
PS:这次发现set容器的iterator有一些神奇的性质,假定有一个迭代器指针it,其后继为it1,在it未更新时,若有一个元素插入在it和it1之间,那么it1仍将认为其后继为it1而非新插入的元素,需要用某些方法更新下it(没有1a的元凶)
1 #include<bits/stdc++.h> 2 #define M 210000 3 using namespace std; 4 struct node{ 5 int x,y; node(){x=y=0;} 6 node(int xx,int yy){x=xx; y=yy;} 7 friend node operator -(node a,node b){return node(a.x-b.x,a.y-b.y);} 8 friend int operator *(node a,node b){ 9 return a.y*b.x-a.x*b.y; 10 } 11 friend bool operator <(node a,node b){ 12 if(a.x==0&&a.y==0) return 0; 13 if(b.x==0&&b.y==0) return 1; 14 if(a.x*b.y==a.y*b.x) return a.x<b.x; 15 return a.y*b.x<a.x*b.y; 16 } 17 }a[M]; 18 set<node> s; 19 20 int n,x,y,m,op[M]={0},id[M]={0}; bool vis[M]={0}; 21 int cj(node a,node b,node c){return (b-a)*(c-a);} 22 double dis(node a,node b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));} 23 double ans=0; 24 25 void ins(node k){ 26 set<node>::iterator now,nowm,nown,pre; 27 nown=nowm=now=s.upper_bound(k); 28 now--; nowm--; nowm--; 29 while(cj(*nowm,*now,k)>0){ 30 ans=ans-dis(*nown,*now)-dis(*now,*nowm)+dis(*nown,*nowm); 31 pre=now; *now--; 32 s.erase(pre); 33 if(nowm==s.begin()) break; 34 *nowm--; 35 } 36 if(cj(*now,k,*nown)>0) return; 37 ans=ans-dis(*nown,*now)+dis(*nown,k)+dis(*now,k); 38 s.insert(k); 39 nowm=now=nown=s.find(k); 40 now++; nown++; nown++; 41 while(cj(*nowm,*now,*nown)>0&&nown!=s.end()){ 42 ans=ans-dis(*nown,*now)-dis(*now,*nowm)+dis(*nown,*nowm); 43 pre=now; *now++; *nown++; 44 s.erase(pre); 45 } 46 } 47 double ansp[M]={0};int use=0; 48 int main(){ 49 scanf("%d%d%d",&n,&x,&y); 50 s.insert(node(0,0)); s.insert(node(n,0)); s.insert(node(x,y)); 51 ans=dis(node(0,0),node(x,y))+dis(node(x,y),node(n,0)); 52 scanf("%d",&n); 53 for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); 54 scanf("%d",&m); 55 for(int i=1;i<=m;i++){ 56 scanf("%d",op+i); 57 if(op[i]==2) continue; 58 scanf("%d",id+i); 59 vis[id[i]]=1; 60 } 61 for(int i=1;i<=n;i++) if(!vis[i]) ins(a[i]); 62 for(int i=m;i;i--){ 63 if(op[i]==2) {ansp[++use]=ans; continue;} 64 if(!vis[id[i]]) continue; 65 ins(a[id[i]]); vis[id[i]]=0; 66 } 67 while(use) printf("%.2lf ",ansp[use--]); 68 }