将问题离线倒序处理,问题变成动态加点维护凸包。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cctype>
#include <set>
#define rep(i, l, r) for(int i=l; i<=r; i++)
#define down(i, l, r) for(int i=l; i>=r; i--)
#define maxn 200009
using namespace std;
inline int read()
{
int x=0, f=1; char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while (isdigit(ch)) x=x*10+ch-'0', ch=getchar();
return x*f;
}
struct P{int x, y;} a[200005], del[100005];
double dis(P a, P b){return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
P operator - (P a, P b){return (P){a.x-b.x, a.y-b.y};}
double operator * (P a, P b){return a.x*b.y-a.y*b.x;}
bool operator < (P a, P b){if (a.x==b.x) return a.y<b.y; else return a.x<b.x;}
set<P> q;
int n, m, Q, b[maxn], t1, t2;
double now=0, res[maxn];
bool mark[maxn];
void insert(P p)
{
set<P>::iterator r=q.lower_bound(p), l=r, t; l--;
if ((*r-*l)*(p-*l)<0) return;
now-=dis(*l, *r);
while (1)
{
t=r++;
if (r==q.end()) break;
if ((*r-p)*(*t-p)>0) break;
now-=dis(*t, *r);
q.erase(t);
}
while (l!=q.begin())
{
t=l--;
if ((*t-p)*(*l-p)>0) break;
now-=dis(*t, *l);
q.erase(t);
}
q.insert(p); l=r=q.find(p); l--; r++;
now+=dis(*l, p)+dis(*r, p);
}
int main()
{
n=read();
q.insert((P){0, 0}); q.insert((P){n, 0});
P bas;
bas.x=read(); bas.y=read(), q.insert(bas);
now+=dis((P){0, 0}, bas)+dis((P){n, 0}, bas);
m=read();
rep(i, 1, m) a[i].x=read(), a[i].y=read();
Q=read();
rep(i, 1, Q)
{
int type=read(), x;
if (type==1) x=read(), del[++t1]=a[x], mark[x]=1;
else b[++t2]=t1;
}
rep(i, 1, m) if (!mark[i]) insert(a[i]);
int T=t1;
down(i, t2, 1)
{
while (T>b[i]) insert(del[T--]);
res[i]=now;
}
rep(i, 1, t2) printf("%.2lf
", res[i]);
return 0;
}