[HAOI2011] 防线修建

传送门
参考博客
练习 S T L STL STL库。动态维护凸包。由于题目要求一个一个删除,可以考虑反过来离线操作,一个一个加回去。
当新增加一个点的时候,往它的左右两边扩张( s e t set set中按照 x x x排好序),看是否需要修改凸包。用叉积判断即可。
注意最开始要加上 d i s ( ( 0 , 0 ) , ( x , y ) ) dis((0,0),(x,y)) dis((0,0),(x,y)) d i s ( ( m , 0 ) , ( x , y ) ) dis((m,0),(x,y)) dis((m,0),(x,y))

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxq=2e5+10;
int del[maxn],tot=0,n,q;double ans[maxq],cur=0.0,m,x,y;
struct Grid{
	double x,y;
	Grid(double X=0,double Y=0){x=X,y=Y;}
	friend inline Grid operator+(const Grid &a,const Grid &b){return Grid(a.x+b.x,a.y+b.y);}
	friend inline Grid operator-(const Grid &a,const Grid &b){return Grid(a.x-b.x,a.y-b.y);}
	friend inline Grid operator*(const Grid &a,const double &b){return Grid(a.x*b,a.y*b);}
	friend inline Grid operator/(const Grid &a,const double &b){return Grid(a.x/b,a.y/b);}
	friend inline double cross(const Grid &a,const Grid &b){return a.x*b.y-a.y*b.x;}
	friend inline double dis(const Grid &a,const Grid &b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
	friend inline bool operator<(const Grid &a,const Grid &b)
		{return (a.x==b.x)?a.y<b.y:a.x<b.x;}
	inline void print(){printf("%.2lf %.2lf\n",x,y);}
}p[maxn];typedef Grid Vector,Point;
struct question{
	int op,id;
	question(int OP=0,int ID=0){op=OP,id=ID;}
}Q[maxq];
set<Point> G;
inline void add(Point x){
	set<Point>::iterator l,r,t;
	l=r=G.upper_bound(x),--l;
	Point A=*l,B=*r;
	if(cross(B-x,A-x)>0) return;
	cur-=dis(*l,*r);
	while(l!=G.begin()){
		t=l,--t;if(cross(*l-x,*t-x)>0) break;
		cur-=dis(*l,*t),G.erase(*l),l=t;
	}
	while(1){
		t=r,++t;
		if(t==G.end()||cross(*t-x,*r-x)>0) break;
		cur-=dis(*r,*t),G.erase(*r),r=t;
	}
	G.insert(x),l=r=G.find(x),--l,++r;
	cur+=dis(x,*l)+dis(x,*r);
}
int main(){
	//freopen("1968.in","r",stdin);
	scanf("%lf%lf%lf",&m,&x,&y);
	G.insert(Point(0,0)),G.insert(Point(m,0)),G.insert(Point(x,y));
	cur+=dis(Point(0,0),Point(x,y))+dis(Point(m,0),Point(x,y));
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%lf%lf",&p[i].x,&p[i].y);
	scanf("%d",&q);
	for(int i=1;i<=q;++i){
		scanf("%d",&Q[i].op);
		if(Q[i].op==1) scanf("%d",&Q[i].id),del[Q[i].id]=1;
	}for(int i=1;i<=n;++i) if(!del[i]) add(p[i]);
	for(int i=q;i>=1;i--){
		if(Q[i].op==2) ans[++tot]=cur;
		else add(p[Q[i].id]);
	}
	for(int i=tot;i>=1;--i)
		printf("%.2lf\n",ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值