BZOJ [HAOI2011]防线修建(动态凸包)

时间:2023-03-09 09:00:36
BZOJ [HAOI2011]防线修建(动态凸包)

听说有一种很高端的东西叫动态凸包维护dp就像学一下,不过介于本人还不会动态凸包就去学了下,还是挺神奇的说,维护上下凸包的写法虽然打得有点多不过也只是维护复制黏贴的事情而已罢了。

先说下动态凸包怎么写吧,搞棵平衡树存上下凸壳然后每次插入一个点就往他左右维护看是否满足凸性否则就弹出,就是这么简单

这道题就是删点然后询问凸壳,那么离线反着做就行了

出题人还是挺良心的直接让你维护上凸壳就行了,还不用管边界条件

用set打了一下,比较慢但还是挺好打的= =

换新blog挺多功能得试试的,现在想搞个像HZWER的那个球还有一个虾米等有时间试试(当然还有头像!!!)

好了不多说了发完睡觉了= =

CODE:

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
using namespace std;
typedef pair<int,int> ii;
typedef set<ii>::iterator iter;
#define fi first
#define se second
#define sqr(x) ((x)*(x))
inline double dist(ii u,ii v) {return sqrt(sqr(u.fi-v.fi)+sqr(u.se-v.se));}
inline int cross(ii x,ii y,ii z) {
return (y.fi-x.fi)*(z.se-x.se)-(y.se-x.se)*(z.fi-x.fi);
}
set<ii> gap;
#define maxn 201000
int a[maxn][],c[maxn][];
bool b[maxn];
double sum,ans[maxn];
inline void del(iter x){
iter u=x,v=x;
u--,v++;
sum-=dist(*u,*x)+dist(*x,*v);
sum+=dist(*u,*v);
gap.erase(x);
}
inline void ins(ii x){
iter it=gap.upper_bound(x);
--it;
iter v=it,u;++v;
if (cross(*it,x,*v)>=) return;
gap.insert(x);
it=gap.find(x);
v=it,u=it;
--u,++v;
sum+=dist(*u,*it)+dist(*it,*v);
sum-=dist(*u,*v);
for (iter v=it,u;;v=it){
++v;u=v;++v;
if (v==gap.end()) break;
if (cross(*it,*u,*v)<) break;
del(u);
}
for (iter v=it,u;;v=it){
--v;
if (v==gap.begin()) break;
u=v;--v;
if (cross(*v,*u,*it)<) break;
del(u);
}
}
int main(){
int n,m,q;
scanf("%d%d%d",&n,&a[][],&a[][]);
scanf("%d",&m);
for (int i=;i<=m;i++) scanf("%d%d",a[i],a[i]+);
scanf("%d",&q);
for (int i=;i<=q;i++) {
scanf("%d",c[i]);
if (c[i][]==) scanf("%d",c[i]+),b[c[i][]]=;
}
gap.insert(ii(,));
gap.insert(ii(n,));
sum=n;
for (int i=;i<=m;i++) if (!b[i]) ins(ii(a[i][],a[i][]));
for (int i=q;i;i--) {
if (c[i][]==) ins(ii(a[c[i][]][],a[c[i][]][]));
else ans[i]=sum;
}
for (int i=;i<=q;i++)
if (ans[i]) printf("%.2lf\n",ans[i]);
return ;
}