2019.02.22【HAOI2011】【BZOJ2300】【洛谷P2521】防线修建(动态凸包)

DarkBZOJ传送门

洛谷传送门


解析:

动态凸包裸题,由于只需要维护一个上凸壳,所以用map水平序维护会比较方便。

细节有点多,慢慢调吧。

动态凸包板子可以看这里:https://blog.csdn.net/zxyoi_dreamer/article/details/87879301


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
	}
	
	inline int getint(){
		re char c;
		re bool f=0;
		while(!isdigit(c=gc()))if(c=='-')f=1;re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return f?-num:num;
	}
}
using namespace IO;

map<int,int> conv;
typedef map<int,int>::iterator point;

inline pair<int,int> operator-(cs pair<int,int> &a,cs pair<int,int> &b){
	return make_pair(a.first-b.first,a.second-b.second);
}

inline ll operator*(cs pair<int,int> &a,cs pair<int,int> &b){
	return (ll)a.first*b.second-(ll)a.second*b.first;
}

inline bool inside(int x,int y){
	if(!conv.size())return false;
	if(x<conv.begin()->first||x>conv.rbegin()->first)return false;
	if(conv.count(x))return conv[x]<=y;
	map<int,int>::iterator r=conv.lower_bound(x),l=r;
	--l;
	return (make_pair(x,y)-*l)*(*r-*l)<=0;
}

inline double dist(cs pair<int,int> &a,cs pair<int,int> &b){
	return sqrt((ll)(a.first-b.first)*(a.first-b.first)+(ll)(a.second-b.second)*(a.second-b.second));
}

double nowc;
inline void ins(int x,int y){
	if(inside(x,y))return ;
	point now=conv.find(x);
	if(now!=conv.end()){
		point pre=now,suf=now;
		--pre,++suf;
		nowc-=dist(*pre,*now)+dist(*suf,*now);
		now->second=y;
		nowc+=dist(*pre,*now)+dist(*suf,*now); 
	}
	else {
		conv[x]=y;
		now=conv.find(x);
		point pre=now,suf=now;
		--pre,++suf;
		nowc-=dist(*pre,*suf);
		nowc+=dist(*pre,*now)+dist(*suf,*now); 
	}
	point cur=conv.lower_bound(x);
	point re i,j;
	for(i=cur,--i,j=i,--j;i!=conv.begin()&&cur!=conv.begin();i=j--)
	if((*i-*cur)*(*j-*cur)>=0){
		nowc-=dist(*i,*j)+dist(*i,*cur);
		nowc+=dist(*j,*cur);
		conv.erase(i);
	}
	else break;
	for(i=cur,++i,j=i,++j;i!=conv.end()&&j!=conv.end();i=j++)
	if((*i-*cur)*(*j-*cur)<=0){
		nowc-=dist(*i,*j)+dist(*i,*cur);
		nowc+=dist(*j,*cur);
		conv.erase(i);
	}
	else break;
}

cs int N=100005;
int n,x[N],y[N];
int First[N];
int q,typ[N<<1],opt[N<<1];

double ans[N<<1];int cnt; 

signed main(){
	n=getint();x[0]=getint(),y[0]=-getint();
	conv[0]=0;
	conv[n]=0;
	conv[x[0]]=y[0];
	nowc=dist(make_pair(0,0),make_pair(x[0],y[0]))+dist(make_pair(x[0],y[0]),make_pair(n,0));
	n=getint();
	for(int re i=1;i<=n;++i)x[i]=getint(),y[i]=-getint();
	q=getint();
	for(int re i=1;i<=q;++i){
		if((typ[i]=getint())==1){
			opt[i]=getint();
			if(!First[opt[i]])First[opt[i]]=i;
		}
	}
	for(int re i=1;i<=n;++i)if(!First[i])ins(x[i],y[i]);
	for(int re i=q;i;--i){
		switch(typ[i]){
			case 1:{
				if(i==First[opt[i]])
				ins(x[opt[i]],y[opt[i]]);
				break;
			}
			case 2:{
				ans[++cnt]=nowc;
				break;
			}
		}
	}
	for(int re i=cnt;i;--i)printf("%.2f\n",ans[i]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值