【BZOJ2300】【HAOI2011】防线修建

题目大意:给你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\n",ansp[use--]);
68 }

 

posted @ 2017-11-23 20:30  AlphaInf  阅读(226)  评论(1编辑  收藏  举报