上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度,如果,这个时候撤销B点的保护,那么防线变成下图
对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数
凸包上删点很难处理,所以我们考虑离线,将删点操作转化为加点操作。
于是现在问题变成了:维护一个支持加点操作的动态凸包。
每次加一个点判断是否在凸包内,然后用set找两边相邻的点,再两边分别维护。
#include
#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 200005
using namespace std;
int n,x,y,m,q;
int opt[maxn];
bool tag[maxn];
double now,ans[maxn];
struct data{int x,y;}a[maxn];
set s;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline double dis(data a,data b)
{
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(double)(a.y-b.y)*(a.y-b.y));
}
inline data operator -(data a,data b)
{
return (data){a.x-b.x,a.y-b.y};
}
inline int operator *(data a,data b)
{
return a.x*b.y-a.y*b.x;
}
inline bool operator <(data a,data b)
{
return a.x==b.x?a.y::iterator l=s.lower_bound(x),r=l,t;
l--;
if ((*r-*l)*(x-*l)<0) return;
now-=dis(*l,*r);
for(;;)
{
t=r;r++;
if (r==s.end()) break;
if ((*r-x)*(*t-x)>0) break;
now-=dis(*t,*r);
s.erase(t);
}
for(;;)
{
if (l==s.begin()) break;
t=l;l--;
if ((x-*l)*(*t-*l)>0) break;
now-=dis(*t,*l);
s.erase(t);
}
s.insert(x);
l=r=s.find(x);l--;r++;
now+=dis(*l,x)+dis(*r,x);
}
int main()
{
n=read();x=read();y=read();
s.insert((data){0,0});s.insert((data){n,0});s.insert((data){x,y});
now=dis((data){0,0},(data){x,y})+dis((data){n,0},(data){x,y});
m=read();
F(i,1,m) a[i].x=read(),a[i].y=read();
q=read();
F(i,1,q)
{
int flg=read();
opt[i]=(flg==2)?0:read();
if (opt[i]) tag[opt[i]]=true;
}
F(i,1,m) if (!tag[i]) add_data(a[i]);
D(i,q,1)
{
if (opt[i]) add_data(a[opt[i]]);
else ans[i]=now;
}
F(i,1,q) if (!opt[i]) printf("%.2lf\n",ans[i]);
return 0;
}