用stl来写凸包,虽然有点慢,然而写着方便~~~
bzoj2003防线修建(权限~(>_<)~)然而我们还有洛谷2521
只有上凸壳,删点,求凸包;
逆着想,可以将询问倒过来做,相当于加点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<map>
#include<vector>
#include<set>
#include<cmath>
#include<algorithm>
using namespace std;
int read()
{
int x=0;
char y;
do y=getchar();while(y>'9'||y<'0');
do x=10*x+y-'0',y=getchar();while(y<='9'&&y>='0');
return x;
}
double now,res[200005];
int T,t1,t2,n,m,k;
int b[200005];
bool pd[100005];
struct P{
int x,y;
}del[100005],a[200005];
set<P>q;
double ds(P a,P b)
{
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool operator<(P a,P b)
{
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
int operator*(P a,P b)
{
return a.x*b.y-a.y*b.x;
}
P operator-(P a,P b)
{
P t;
t.x=a.x-b.x;
t.y=a.y-b.y;
return t;
}
void insert(int a,int b)
{
P x=(P){a,b};
set<P>::iterator r=q.lower_bound(x),l=r,t;//r是x右边的一个点,l是左边的点
l--;
if((*r-*l)*(x-*l)<0)return;//要删的点在凸包里面;1
now-=ds(*l,*r);//把原来两点间距离删掉
q.insert(x);
while(1)
{
t=r,r++;
if(r==q.end())break;
if((*r-x)*(*t-x)>0)break;//噫...右手定则手动模拟...
now-=ds(*t,*r);
q.erase(t);
}
while(l!=q.begin())
{
t=l;l--;
if((*t-x)*(*l-x)>0)break;
now-=ds(*t,*l);
q.erase(t);
}
q.insert(x);
l=r=t=q.find(x);
l--,r++;
now+=ds(*l,x)+ds(*r,x);
}
int main()
{
n=read();
q.insert((P){0,0}),q.insert((P){n,0});
P cap;
cap.x=read(),cap.y=read();
q.insert(cap);
now+=ds((P){0,0},cap);
now+=ds((P){n,0},cap);
m=read();
for(int i=1;i<=m;i++)
{
a[i].x=read();a[i].y=read();
}
k=read();
short type;
int x;
for(int i=1;i<=k;i++)
{
type=read();
if(type==1)
{
x=read();
del[++t1]=a[x];
pd[x]=1;
}
else b[++t2]=t1;
}
for(int i=1;i<=m;i++)
if(!pd[i])insert(a[i].x,a[i].y);
int T=t1;
for(int i=t2;i>=1;i--)//需要询问的,从后往前添加在询问之后的城市
{
while(T>b[i])
{
insert(del[T].x,del[T].y);
T--;
}
res[i]=now;
}
for(int i=1;i<=t2;i++)
printf("%.2lf\n",res[i]);
return 0;
}