上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度,如果,这个时候撤销B点的保护,那么防线变成下图
对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数
凸包上删点很难处理,所以我们考虑离线,将删点操作转化为加点操作。
于是现在问题变成了:维护一个支持加点操作的动态凸包。
每次加一个点判断是否在凸包内,然后用set找两边相邻的点,再两边分别维护。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<set> #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<data> 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<b.y:a.x<b.x; } inline void add_data(data x) { set<data>::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; }