把操作离线,倒着做,这样就是加点维护凸包了。
可以用set维护一下当前凸包上的点
然后每次新加一个点时判断是在凸包内还是凸包外
如果在凸包外,就要重新维护上凸壳,往两边删点,直到再次构成凸壳。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m;
double ans=0;
inline double sqr(double x){return x*x;}
struct P{
double x,y;
P(double _x=0,double _y=0){x=_x;y=_y;}
friend bool operator<(P a,P b){return a.x==b.x?a.y<b.y:a.x<b.x;}
friend double dis(P a,P b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
friend double det(P a,P b){return a.x*b.y-a.y*b.x;}
friend P operator-(P a,P b){return P(a.x-b.x,a.y-b.y);}
}a[N],O,T;
bool mk[N];
struct quer{
int op,id;
}qq[N<<1];
set<P>st;set<P>::iterator it,pre,succ;
vector<double>Ans;
inline void ins(P x){
succ=st.lower_bound(x);
pre=succ;--pre;
if(det(x-*pre,*succ-*pre)>0) return;
ans-=dis(*pre,*succ);
while(1){
it=succ;++succ;
if(succ==st.end()) break;
if(det(*succ-x,*it-x)>0) break;
ans-=dis(*it,*succ);st.erase(it);
}while(1){
if(pre==st.begin()) break;
it=pre;--pre;
if(det(*it-x,*pre-x)>0) break;
ans-=dis(*it,*pre);st.erase(it);
}succ=st.lower_bound(x);pre=succ;--pre;
ans+=dis(x,*pre);ans+=dis(x,*succ);st.insert(x);
}
int main(){
// freopen("a.in","r",stdin);
T.x=read();st.insert(O);st.insert(T);
P cap;cap.x=read();cap.y=read();st.insert(cap);
ans+=dis(O,cap);ans+=dis(T,cap);n=read();
for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read();
m=read();
for(int i=1;i<=m;++i){
qq[i].op=read();if(qq[i].op==2) continue;
qq[i].id=read();mk[qq[i].id]=1;
}for(int i=1;i<=n;++i) if(!mk[i]) ins(a[i]);
for(int i=m;i>=1;--i){
if(qq[i].op==2) Ans.push_back(ans);
else ins(a[qq[i].id]);
}reverse(Ans.begin(),Ans.end());
for(vector<double>::iterator it=Ans.begin();it!=Ans.end();++it)
printf("%.2lf\n",*it);
return 0;
}