【SDOI2012】拯救小云公主(Voronoi图)(Delaunay三角剖分)

传送门


题解:

D剖练习题,没什么好讲的。看问题显然是求Voronoi图,然而我们要用的只有V图中点的相邻关系,直接用D剖求一下就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define db double
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}template<typename T>T get_integer(){
		char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T num=c^48;
		while(isdigit(c=gc()))num=((num+(num<<2))<<1)+(c^48);return f?-num:num;
	}inline int gi(){return get_integer<int>();}
}using namespace IO;

using std::cerr;
using std::cout;

cs int N=3e3+7;

struct Pnt{
	db x,y;Pnt(){}Pnt(db _x,db _y):x(_x),y(_y){}
	friend Pnt operator+(cs Pnt &a,cs Pnt &b){return Pnt(a.x+b.x,a.y-b.y);}
	friend Pnt operator-(cs Pnt &a,cs Pnt &b){return Pnt(a.x-b.x,a.y-b.y);}
	friend db operator*(cs Pnt &a,cs Pnt &b){return a.x*b.y-a.y*b.x;}
	friend db dot(cs Pnt &a,cs Pnt &b){return a.x*b.x+a.y*b.y;}
	db len()cs{return sqrt(x*x+y*y);}
};

struct pt{
	db x,y,z;pt(){}pt(db _x,db _y,db _z):x(_x),y(_y),z(_z){}
	friend pt operator+(cs pt &a,cs pt &b){return pt(a.x+b.x,a.y+b.y,a.z+b.z);}
	friend pt operator-(cs pt &a,cs pt &b){return pt(a.x-b.x,a.y-b.y,a.z-b.z);}
	friend pt operator*(cs pt &a,cs pt &b){return pt(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-b.x*a.y);}
	friend db dot(cs pt &a,cs pt &b){return a.x*b.x+a.y*b.y+a.z*b.z;}
	pt operator-()cs{return pt(-x,-y,-z);}
	db len()cs{return sqrt(x*x+y*y+z*z);}
};

inline db crs(cs Pnt &a,cs Pnt &b,cs Pnt &c){
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
inline pt crs(cs pt &a,cs pt &b,cs pt &c){
	return (b-a)*(c-a);
}
inline pt trans(cs Pnt &a){
	return pt(a.x,a.y,a.x*a.x+a.y*a.y);
}
inline bool incir(cs Pnt &D,cs Pnt &A,cs Pnt &B,cs Pnt &C){
	pt a=trans(A),b=trans(B),c=trans(C),d=trans(D);
	pt dir=crs(a,b,c);if(dir.z>0)dir=-dir;return dot(dir,d-a)>0;
}

cs int M=N<<3|7;

int n;db X,Y;

Pnt p[N];
int bin[M],tot;
int pr[M],nx[M];
int to[M],rev[M];

inline int ins_pr(int u,int v){
	int e=bin[++tot];
	pr[e]=pr[u],nx[e]=u;
	nx[pr[e]]=e,pr[u]=e;
	to[e]=v;return e;
}
inline int ins_nx(int u,int v){
	int e=bin[++tot];
	nx[e]=nx[u],pr[e]=u;
	pr[nx[e]]=e,nx[u]=e;
	to[e]=v;return e;
}
inline void del(int e){
	pr[nx[e]]=pr[e];
	nx[pr[e]]=nx[e];
	bin[tot--]=e;
}

inline db crs(int a,int b,int c){
	return crs(p[a],p[b],p[c]);
}
inline bool incir(int d,int a,int b,int c){
	return incir(p[d],p[a],p[b],p[c]);
}

void delaunay(int l,int r){
	if(l==r)return ;
	if(l+1==r){
		int el=ins_nx(l,r);
		int er=ins_pr(r,l);
		rev[el]=er,rev[er]=el;
		return ;
	}int mid=(l+r)>>1,tp=0;static int st[N];
	delaunay(l,mid);delaunay(mid+1,r);
	for(int re i=l;i<=r;++i){
		while(tp>1&&crs(st[tp-1],st[tp],i)<0)--tp;
		st[++tp]=i;
	}int nl=0,nr=0;
	for(int re i=1;i<=tp;++i)
		if(st[i]<=mid&&st[i+1]>mid)
			{nl=st[i],nr=st[i+1];break;}
	int sl,sr;
	for(sl=pr[nl];sl!=nl;sl=pr[sl])
		if(crs(nl,nr,to[sl])>=0)break;
	for(sr=nx[nr];sr!=nr;sr=nx[sr])
		if(crs(nr,nl,to[sr])<=0)break;
	int el=ins_nx(sl,nr),er=ins_pr(sr,nl);
	rev[el]=er,rev[er]=el;
	while(true){
		bool cl=false,cr=false;
		for(;sl!=nl;sl=pr[sl]){
			if(crs(nl,nr,to[sl])<=0){
				if(p[to[sl]].x>=p[nl].x)continue;
				break;
			}
			if(pr[sl]!=nl&&incir(to[pr[sl]],nl,nr,to[sl]))
				del(rev[sl]),del(sl);
			else {cl=true;break;}
		}
		for(;sr!=nr;sr=nx[sr]){
			if(crs(nr,nl,to[sr])>=0){
				if(p[to[sr]].x<p[nr].x)continue;
				break;
			}
			if(nx[sr]!=nr&&incir(to[nx[sr]],nr,nl,to[sr]))
				del(rev[sr]),del(sr);
			else {cr=true;break;}
		}
		if(!cl&&!cr)break;
		if(!cr||(cl&&!incir(to[sr],nl,nr,to[sl]))){
			nl=to[sl];
			for(sl=pr[nl];sl!=nl;sl=pr[sl])
				if(crs(nl,nr,to[sl])>=0||p[to[sl]].x<p[nl].x)break;
			el=ins_nx(sl,nr),er=ins_pr(sr,nl);
			rev[el]=er,rev[er]=el;
		}else {
			nr=to[sr];
			for(sr=nx[nr];sr!=nr;sr=nx[sr])
				if(crs(nr,nl,to[sr])<=0||p[to[sr]].x>p[nr].x)break;
			el=ins_nx(sl,nr),er=ins_pr(sr,nl);
			rev[el]=er,rev[er]=el;
		}
	}
}

struct edge{int u,v;db w;};
std::vector<edge> E;int fa[N];
inline int gf(int u){while(u!=fa[u])u=fa[u]=fa[fa[u]];return u;} 

void Main(){
	n=gi(),X=gi(),Y=gi();
	for(int re i=1;i<=n;++i)p[i].x=gi(),p[i].y=gi();
	tot=n;for(int re i=1;i<M;++i)bin[i]=i;
	for(int re i=1;i<=n;++i)pr[i]=nx[i]=i;
	std::sort(p+1,p+n+1,[](cs Pnt &a,cs Pnt &b){
		return a.x==b.x?(a.y<b.y):(a.x<b.x);
	});delaunay(1,n);for(int re i=1;i<=n;++i){
		E.push_back({i,n+1,std::min(p[i].x-1,Y-p[i].y)});
		E.push_back({i,n+2,std::min(p[i].y-1,X-p[i].x)});
		for(int re e=nx[i];e!=i;e=nx[e])if(to[e]>i)
			E.push_back({i,to[e],(p[i]-p[to[e]]).len()*0.5});
	}std::sort(E.begin(),E.end(),[](cs edge &a,cs edge &b){return a.w<b.w;});
	for(int re i=1;i<=n+2;++i)fa[i]=i;
	for(auto &e:E)if(gf(e.u)!=gf(e.v)){
		fa[gf(e.u)]=gf(e.v);
		if(gf(n+1)==gf(n+2)){
			printf("%.2lf\n",e.w);return ;
		}
	}
}

void file(){
#ifdef zxyoi
	freopen("dis.in","r",stdin);
#endif
}
signed main(){file();Main();return 0;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值