bzoj 2300 [HAOI2011]防线修建 set动态维护凸包
题目大意
动态删点,求凸包周长
分析
反过来变成动态加点
用set维护平衡树
具体是找到凸包上左右两点
拆开
就可以把左边当作顺时针求的一个凸包,右边当作逆时针求的一个凸包,像栈那样出set就好了
注意新点在凸包内不用管它
每个点进一次出一次
\(O(n \log n)\)
solution
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <set>
using namespace std;
typedef double db;
const db eps=1e-7;
const int M=200007;
inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
}
db sum;
int n,m;
int kd[M],opr[M];
bool vis[M];
db ans[M];
struct pt{
db x,y;
pt(db _x=0.0,db _y=0.0){x=_x; y=_y;}
}p[M];
/*精度已经把我搞啥了我都不知道加不加,加了set直接炸
bool eq(db x,db y){return fabs(x-y)<=eps;}
bool neq(db x,db y){return !eq(x,y);}
bool le(db x,db y){return eq(x,y)||x<y;}
bool ge(db x,db y){return eq(x,y)||x>y;}
*/
pt operator -(pt x,pt y){return pt(x.x-y.x,x.y-y.y);}
pt operator +(pt x,pt y){return pt(x.x+y.x,x.y+y.y);}
pt operator *(pt x,db d){return pt(x.x*d,x.y*d);}
pt operator /(pt x,db d){return pt(x.x/d,x.y/d);}
bool operator <(pt x,pt y){if(x.x!=y.x)return x.x<y.x;return x.y<y.y;}
db dot(pt x,pt y){
return x.x*y.x+x.y*y.y;
}
db cross(pt x,pt y){
return x.x*y.y-x.y*y.x;
}
db area(pt x,pt y,pt z){
return cross(y-x,z-x);
}
db length(pt x){
return sqrt(dot(x,x));
}
set<pt>S;
typedef set<pt>::iterator its;
void gao(pt x){
its r=S.lower_bound(x);
its l=r; --l;
if(area(*l,x,*r)>=0) return;//凸包内
sum-=length(*r-*l);
its tp;
while(1){
tp=r;
++r;
if(r==S.end()) break;
if(area(*r,*tp,x)<=0){
sum-=length(*tp-*r);
S.erase(tp);
}
}
while(1){
if(l==S.begin()) break;
tp=l;
--l;
if(area(*l,*tp,x)>=0){
sum-=length(*tp-*l);
S.erase(tp);
}
else break;
}
S.insert(x);
l=r=S.find(x);
l--; r++;
sum+=length(x-*l);
sum+=length(x-*r);
}
int main(){
int i,z,x,y;
z=rd(),x=rd(),y=rd();
pt nw=pt(0,0);
S.insert(nw);
nw=pt(z,0);
S.insert(nw);
nw=pt(x,y);
S.insert(nw);
sum=length(pt(x,y))+length(pt(z-x,y));
n=rd();
for(i=1;i<=n;i++){
x=rd(),y=rd();
p[i]=pt(x,y);
}
m=rd();
for(i=1;i<=m;i++){
kd[i]=rd();
if(kd[i]==1){
opr[i]=rd();
vis[opr[i]]=1;
}
}
for(i=1;i<=n;i++)
if(!vis[i]) gao(p[i]);
for(i=m;i>0;i--){
if(kd[i]==2) ans[i]=sum;
else gao(p[opr[i]]);
}
for(i=1;i<=m;i++) if(kd[i]==2) printf("%.2lf\n",ans[i]);
return 0;
}