给定 (n) 个点,有 (m) 次操作,每次指定一个点将其删去,或询问当前上凸包的周长。有 ((0,0),(n,0),(x,y)) 三个点不会被删去,且所有点的 (x) 坐标都位于 ((0,n)),所有点的 (y) 坐标都位于 ((0,+infty))
Solution
逆序处理,就是一个动态凸包的裸题
注意可能会有重复,要先处理一下
有些没被删过的点要提前先加进去
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
struct point {
int x,y;
point(){}
point(int a,int b){x=a;y=b;}
bool operator != (const point &a) const {return (x!=a.x)||(y!=a.y);};
bool operator < (const point &a) const {return (x==a.x)?(y<a.y):(x<a.x);}
point operator - (const point &a) const {return point(x-a.x,y-a.y);}
int operator * (const point &a) const {return x*a.y-y*a.x;}
} p[N];
double dis(point a,point b) {return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));}
set<point> s;
double ans;
int n;
void add(point p) {
point a,b,c;
auto it=s.upper_bound(p);
b=*it;
--it;
a=*it;
if(p.x==b.x || (p-a)*(b-p)>=0) return;
ans-=dis(a,b);
while(a!=(point){0,0}) {
it--; c=*it;
if((a-c)*(p-a)>=0) {
ans-=dis(a,c);
s.erase(s.find(a));
a=c;
}
else break;
}
it=s.find(b);
while(b!=(point){n,0}) {
it++; c=*it;
if((b-p)*(c-b)>=0) {
ans-=dis(b,c);
s.erase(s.find(b));
b=c;
}
else break;
}
ans+=dis(a,p)+dis(p,b);
s.insert(p);
}
int m,q,x[N],y[N],X,Y,fg[N];
vector <double> o;
signed main() {
cin>>n>>X>>Y>>m;
s.insert({0,0});
s.insert({n,0});
s.insert({X,Y});
ans=dis((point){0,0},(point){X,Y})+dis((point){n,0},(point){X,Y});
for(int i=1;i<=m;i++) {
cin>>p[i].x>>p[i].y;
}
cin>>q;
for(int i=1;i<=q;i++) {
cin>>x[i];
if(x[i]==1) {
cin>>y[i];
if(fg[y[i]]==0) {
fg[y[i]]=1;
}
else x[i]=0;
}
}
for(int i=1;i<=m;i++) if(fg[i]==0) add(p[i]);
for(int i=q;i>=1;--i) {
if(x[i]==1) {
add(p[y[i]]);
}
if(x[i]==2) {
o.push_back(ans);
}
}
while(o.size()) printf("%.2lf
",o.back()), o.pop_back();
}