BSOJ5458 [NOI2018模拟5]三角剖分Bsh 分治最短路

题意简述

给定一个正\(n\)边形及其三角剖分,每条边的长度为\(1\),给你\(q\)组询问,每次询问给定两个点\(x_i\)\(y_i\)的最短距离。

做法

显然正多边形的三角剖分是一个平面图,每一条剖分的边可以将正多边形分成有一条重边的两个独立的新多边形,显然这一个过程是可以用分治来实现的。

我们对于分治过程中的多边形进行重新编号,找到两端点数最平均的边割去,对于点集\(V\),边集\(E\)和询问集\(Q\)分别开三个vector传入函数中。

如果点集的大小等于了\(3\),我们就可以对单个三角形进行直接计算,否则对于集合进行左右的分治,贡献大小使用两次bfs计算,时间复杂度\(O(n \log{n})\)

代码实现

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define in inline
#define ll long long
#define ak *
#define db double
in char getch()
{
	static char buf[1<<12],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;
}
char qwq;
#define gc() getch()
in int read()
{
	re cz=0,ioi=1;qwq=gc();
	while(qwq<'0'||qwq>'9') ioi=qwq=='-'?~ioi+1:1,qwq=gc();
	while(qwq>='0'&&qwq<='9') cz=(cz<<3)+(cz<<1)+(qwq^48),qwq=gc();
	return cz ak ioi;
}
#define vec vector
#define pb push_back
const int N=6e4+5;
int n,m,h[N],cnt,dx[N],dy[N],ans[N<<1],siz[N],le[N],ri[N],vis[N];
struct did{int next,to;}e[N<<2];
struct edge{int u,v;};
struct que{int a,b,id;};
vec<edge>ed;
vec<que>qr;
vec<int>ve;
in void Add(re x,re y) {e[++cnt]=(did){h[x],y},h[x]=cnt;}
in void add(re x,re y) {Add(x,y);Add(y,x);}
queue<int>q;
in void bfs(re s,re *dis)
{
	dis[s]=0;q.push(s);
	while(!q.empty())
	{
		re u=q.front();q.pop();
		for(re i=h[u],v;v=e[i].to,i;i=e[i].next)
		if(dis[v]>=1e9&&vis[v]) dis[v]=dis[u]+1,q.push(v);
	}	
}
void divide(vec<int>v,vec<edge>ed,vec<que>qr)
{
	if(!qr.size()) return;
	if(v.size()==3)
	{
		for(re i=0;i<qr.size();i++)
		ans[qr[i].id]=((qr[i].a==qr[i].b)^1);
		return;
	}
	vec<int>v1,v2;v1.clear(),v2.clear();
	vec<edge>e1,e2;e1.clear(),e2.clear();
	vec<que>q1,q2;q1.clear(),q2.clear();
	re n=v.size(),m=ed.size();
    for(re i=0;i<n;i++) siz[v[i]]=0;siz[v[0]]=1;
    for(re i=1;i<n;i++) siz[v[i]]=siz[v[i-1]]+1;
    re x=0,y=0,minn=1e9;
    for(re i=0;i<m;i++) 
	{
        re u=ed[i].u,v=ed[i].v,len=siz[v]-siz[u]-1;
        if(max(len,n-2-len)<minn) 
		minn=max(len,n-2-len),x=u,y=v;
	}
	for(re i=0;i<n;i++)
	{
		if(v[i]>=x&&v[i]<=y) le[v[i]]=1,v1.pb(v[i]);
		if(v[i]<=x||v[i]>=y) ri[v[i]]=1,v2.pb(v[i]);
	}
	for(re i=0;i<m;i++)
	{
		re u=ed[i].u,v=ed[i].v;
		if(le[u]&&le[v]) e1.pb(ed[i]);
		if(ri[u]&&ri[v]) e2.pb(ed[i]);
	}
	for(re i=0;i<qr.size();i++)
	{
		re a=qr[i].a,b=qr[i].b;
		if(le[a]&&le[b]) q1.pb(qr[i]);
		if(ri[a]&&ri[b]) q2.pb(qr[i]);
	}	
	for(re i=0;i<n;i++) vis[v[i]]=1,dx[v[i]]=dy[v[i]]=1e9;
	bfs(x,dx);bfs(y,dy);
	for(re i=0;i<qr.size();i++)
	{
		re a=qr[i].a,b=qr[i].b,id=qr[i].id;
		re lenx=dx[a]+dx[b],leny=dy[a]+dy[b];
		ans[id]=min(min(ans[id],min(lenx,leny)),min(dx[a]+dy[b],dx[b]+dy[a])+1);
	}
	for(re i=0;i<n;i++) vis[v[i]]=le[v[i]]=ri[v[i]]=0;
	divide(v1,e1,q1);divide(v2,e2,q2);
}	
int main()
{
	freopen("bsh.in","r",stdin);
	freopen("bsh.out","w",stdout);
	n=read();
	for(re i=1;i<=n;i++) add(i,i+1-n*(i==n));
	for(re i=1;i<=n-3;i++)
	{
		re x=read(),y=read();
		add(x,y);if(x>y) swap(x,y);
		ed.pb((edge){x,y});
	}
	for(re i=1;i<=n;i++) ve.pb(i);
	m=read();
	for(re i=1;i<=m;i++) 
	{
		re x=read(),y=read();
		if(x>y) swap(x,y);
		qr.pb((que){x,y,i});
	}
	memset(ans,127,sizeof(ans));
	divide(ve,ed,qr);
	for(re i=1;i<=m;i++) printf("%d\n",ans[i]);
}
posted @ 2019-07-11 16:25  disangan233  阅读(373)  评论(0编辑  收藏  举报
Live2D