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;
}
posted @ 2017-02-23 07:35  _zwl  阅读(449)  评论(0编辑  收藏  举报