[BZOJ3199][半平面交][最短路]SDOI2013:逃考

BZOJ掛,鏈自找

很容易發現兩個點連線的中垂線就是劃分兩個點控制區域的直線
那對於每個點處理處它與其他所有點的連線的中垂線,加上邊界四條線做半平面交即可知道這個點的控制區域
然後這個點與所有剩下的直線所代表的點連邊,跑最短路即可

Code:

#include<bits/stdc++.h>
#define eps 1e-9
#define db double
#define mp make_pair
#define fi first
#define se second
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=2e5+5;
namespace sssp{
	int s;
	int vis[N<<1],head[N],nxt[N<<1],etot=0;
	inline void add(int x,int y){vis[++etot]=y;nxt[etot]=head[x];head[x]=etot;}
	int d[N],pt[N];
	priority_queue<pair<int,int> >q;
	inline void dijkstra(){
		memset(d,0x3f,sizeof(d));
		memset(pt,0,sizeof(pt));
		d[s]=0;q.push(mp(0,s)); 
		while(!q.empty()){
			int x=q.top().se;q.pop();pt[x]=1;
			for(int i=head[x];i;i=nxt[i]){
				int y=vis[i];
				if(pt[y]) continue;
				if(d[y]>d[x]+1){
					d[y]=d[x]+1;
					q.push(mp(-d[y],y));
				}
			}
		}
	}
}
using namespace sssp;
namespace half_plane_intersection{
	bool fcmp(double a,double b){return fabs(b-a)<eps;}
	struct point{
		db x,y;
		point(){}
		point(db _x,db _y):x(_x),y(_y){}
		friend inline point operator + (const point &a,const point &b){return point(a.x+b.x,a.y+b.y);}
		friend inline point operator - (const point &a,const point &b){return point(a.x-b.x,a.y-b.y);}
		friend inline point operator * (const point &a,const db &b){return point(a.x*b,a.y*b);}
		friend inline db operator * (const point &a,const point &b){return a.x*b.y-a.y*b.x;}
		inline point ref(){return point(y,-x);}
	}p[N];
	struct line{
		point x,y;
		db ang;
		int id;
		line(){}
		line(point _x,point _y):x(_x),y(_y),ang(atan2(y.y-x.y,y.x-x.x)){}
	}l[N];
	inline bool lft(line a,point b){return (b-a.x)*(a.y-a.x)+eps>0;}
	inline bool cmp(line a,line b){
		if(fcmp(a.ang,b.ang)) return lft(a,b.y);
		return a.ang<b.ang;
	}
	point itse(line a,line b){
		point bs=a.y-a.x;
		db tmp=((b.x-a.x)*bs)/(bs*(b.y-b.x));
		return b.x+(b.y-b.x)*tmp;
	}
	inline point mid(point x,point y){return point((x.x+y.x)/2,(x.y+y.y)/2);}
	inline line get(point a,point b){
		point c=mid(a,b);
		return line(c,c+(b-a).ref()); 
	}
	int n,tot;
	db ans=0,sum=0;
	point st;
	int q[N];
	inline void hp(int x){
		int hd=1,ta=2;
		sort(l+1,l+tot+1,cmp);
		int pos=1;
		for(int i=2;i<=tot;i++) if(fabs(l[i].ang-l[pos].ang)>0) l[++pos]=l[i];
		tot=pos;
		q[1]=1,q[2]=2;
		for(int i=3;i<=tot;i++){
			while(hd<ta && lft(l[i],itse(l[q[ta-1]],l[q[ta]]))) --ta;
			while(hd<ta && lft(l[i],itse(l[q[hd+1]],l[q[hd]]))) ++hd;
			q[++ta]=i;
		}
		while(hd<ta && lft(l[q[hd]],itse(l[q[ta-1]],l[q[ta]]))) --ta;
		for(int i=hd;i<=ta;i++) add(x,l[q[i]].id);
		if(ta-hd<2) return;
		int f=1;
		for(int i=hd;i<=ta;i++) if(lft(l[q[i]],st)) f=0;
		if(f) s=x;
	}
	db xx,yy;
	inline void init(int id){
		tot=0;
		point p1=point(0,0),p2=point(xx,0),p3=point(xx,yy),p4=point(0,yy);
		l[++tot]=line(p1,p2),l[++tot]=line(p2,p3),l[++tot]=line(p3,p4),l[++tot]=line(p4,p1); 
		for(int i=1;i<=4;i++) l[i].id=n+1;
		for(int i=1;i<=n;i++) if(i!=id) l[++tot]=get(p[i],p[id]),l[tot].id=i;
	}
}
using namespace half_plane_intersection;
int main(){
	int t=read();
	while(t--){
		memset(head,0,sizeof head),etot=0;
		n=read();
		scanf("%lf%lf%lf%lf",&xx,&yy,&st.x,&st.y);
		for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
		for(int i=1;i<=n;i++) init(i),hp(i);
		dijkstra();
		if(d[n+1]==1061109567) cout<<"0"<<"\n";
		else cout<<d[n+1]<<"\n";
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章