动态凸包就是可以支持动态插入点,维护凸包信息的一类问题
又考到了,又被炸飞了(然而其实弱的连凸包性质都看不出来
注意只能支持动态插入点,而不支持动态删除和插入
不过删除的话如果不强制在线反过来就是插入啊OwO
不是很喜欢水平序的动态凸包,因为要维护上下两个凸壳好烦
所以就学了一发极角序
大概做法是以极角序为键值用平衡树维护凸包上的点
每次插入的时候找到插入点的前驱后继,用叉积判断是否在内部
如果不在就插入,插入之后不断的判断插入后前驱是否在凸包内和后继是否在凸包内
并且不断的删除直至不能删除为止
因为只需要支持插入,删除,求前驱,求后继,所以直接用set就可以维护了
需要注意的几个地方:
1、一开始取的基准点必须要在凸包内部,因为只支持插入所以凸包可能变大,所以找一开始三个点的内部就可以了
2、排序的时候极角序相同按到基准点的长度排序
3、凸包是环状的,所以前驱和后继也是环状的,判一下就可以了
BZOJ 2300 防线修建
真是一道好的模板题目啊OwO
没有下凸壳,没有边界问题,一开始还给三个点
然而问题是写完这道题目写其他题目会被各种边界炸飞
题目显然是要求动态删除一个点,查询凸包周长
时间倒流一下就是动态凸包的裸题了,至于周长什么的插入删除维护一下就可以了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<set>
#include<cmath>
#define eps 1e-10
using namespace std;
const int maxn=100010;
int n,x,y,m,q;
bool vis[maxn];
double ans=0;
struct Point{
double x,y,ang,len;
Point(double x=0,double y=0,double ang=0,double len=0):x(x),y(y),ang(ang),len(len){}
void read(){scanf("%lf%lf",&x,&y);}
}a[maxn],o;
typedef Point Vector;
bool operator <(const Point &A,const Point &B){
if(fabs(A.ang-B.ang)<eps)return A.len<B.len;
return A.ang<B.ang;
}
Vector operator -(const Point &A,const Point &B){return Vector(A.x-B.x,A.y-B.y);}
double Cross(const Point &A,const Point &B){return A.x*B.y-A.y*B.x;}
double Dot(const Point &A,const Point &B){return A.x*B.x+A.y*B.y;}
double Get_len(const Point &A){return sqrt(Dot(A,A));}
double sqr(double x){return x*x;}
struct ASK{
int type,u;
}Q[maxn];
int top=0;
double Ans[maxn];
set<Point>S;
set<Point>::iterator it,pre,tmp;
set<Point>::iterator Get_pre(set<Point>::iterator it){
if(it==S.begin())it=S.end();
it--;
return it;
}
set<Point>::iterator Get_suf(set<Point>::iterator it){
it++;
if(it==S.end())it=S.begin();
return it;
}
void Get_insert(const Point &p){
it=S.lower_bound(p);
if(it==S.end())it=S.begin();
pre=Get_pre(it);
if(Cross((*it)-(*pre),p-(*pre))>=0)return;
ans-=Get_len((*it)-(*pre));
ans+=Get_len(p-(*it))+Get_len(p-(*pre));
S.insert(p);tmp=Get_pre(pre);
while(Cross(p-(*pre),(*pre)-(*tmp))>=0){
ans=ans-Get_len(p-(*pre))-Get_len((*pre)-(*tmp));
ans=ans+Get_len(p-(*tmp));
S.erase(pre);
pre=tmp;tmp=Get_pre(pre);
}tmp=Get_suf(it);
while(Cross(p-(*it),(*it)-(*tmp))<=0){
ans=ans-Get_len(p-(*it))-Get_len((*it)-(*tmp));
ans=ans+Get_len(p-(*tmp));
S.erase(it);
it=tmp;tmp=Get_suf(it);
}return;
}
int main(){
scanf("%d%d%d",&n,&x,&y);
a[0]=Point(0,0);a[1]=Point(n,0);a[2]=Point(x,y);
ans+=Get_len(a[2]-a[0])+Get_len(a[2]-a[1]);
for(int i=0;i<3;++i)o.x+=a[i].x,o.y+=a[i].y;
o.x/=3;o.y/=3;
for(int i=0;i<3;++i){
a[i].ang=atan2(a[i].y-o.y,a[i].x-o.x);
a[i].len=Get_len(a[i]-o);
S.insert(a[i]);
}scanf("%d",&m);
for(int i=1;i<=m;++i){
a[i].read();
a[i].ang=atan2(a[i].y-o.y,a[i].x-o.x);
a[i].len=Get_len(a[i]-o);
}
scanf("%d",&q);
for(int i=1;i<=q;++i){
scanf("%d",&Q[i].type);
if(Q[i].type==1)scanf("%d",&Q[i].u),vis[Q[i].u]=true;
}
for(int i=1;i<=m;++i)if(!vis[i])Get_insert(a[i]);
for(int i=q;i>=1;--i){
if(Q[i].type==2)Ans[++top]=ans;
else Get_insert(a[Q[i].u]);
}
for(int i=top;i>=1;--i)printf("%.2lf\n",Ans[i]);
return 0;
}
codeforces 70D
这个是真动态凸包裸题了
注意边界问题就好啦OwO
代码貌似因为某些奇怪的原因找不到啦QAQ
跟上面几乎是一模一样的
OwO 自己计算几何太渣了
然而NOI会不会考呢?思考ing