UOJ#57./bzoj3051 【WC2013】(平面图转对偶图)

我极度推荐去Luogu交,完全不要管什么UOJ

平面图转对偶图
这个实现。。。太恶心了。
1:其实从每条边开始走最左转线,是不会走到别的平面的边上的,第一次走到走过的边一定是开始的那条边。
2:找最左转线的时候可以把每个点出发的边按极角排序,找下一条边就是找当前边的反向边的同出发点的极角更小的第一条边。
3:因为平面图的边不会在中途相交,在中途我们可以用set维护斜率和截距(斜率为无限大的不需要考虑)
4:set插入时会返回一个pair,first装的是迭代器,存起来,删除可以删迭代器。。。。(我的精度啊。。。。。)
5:UOJ的hack数据并没有按照题面说的来。。。。。。还卡精度(计算几何的1e9.。。。。。)
6:对偶图不算无限区域可能不联通。。。。
7:改着改着就6KB了。

#include
#define maxn 600005
#define eps 1e-8
#define eps2 1e-10
#define eps3 1e-10
using namespace std;
inline int dcmp(double x)
{ 
	if(x < -eps) return -1;
	if(x > eps) return 1;
	return 0;
}
inline int dcmp2(double x)
{ 
	if(x < -eps2) return -1;
	if(x > eps2) return 1;
	return 0;
}
inline int dcmp3(double x)
{ 
	if(x < -eps3) return -1;
	if(x > eps3) return 1;
	return 0;
}

int n,m,q;
int u[maxn<<1],v[maxn<<1],h[maxn<<1],id[maxn<<1];
int bl[maxn<<1],cnt_bl,infarea;
double alp[maxn<<1];
bool cmp1(const int &u,const int &v){ return dcmp2(alp[u]-alp[v])==0?u<v:alp[u]<alp[v]; }

struct Point
{
	double x,y;
	Point(double x=0,double y=0):x(x),y(y){}
	Point operator +(const Point &B)const{ return Point(x+B.x,y+B.y); }
	Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); }
	double operator *(const Point &B)const{return x*B.y-y*B.x;}
	bool operator <(const Point &B)const{ return dcmp(x-B.x)==0 ? y<B.y:x<B.x; }
}P[maxn];

bool cmp2(const int &u,const int &v){ return P[u] < P[v]; }

vector<int>G[maxn];
int rk[maxn];

int loc[maxn];
struct Query
{
	Point A;
	int id;
	bool operator <(const Query &B)const{ return dcmp(A.x-B.A.x) == 0 ? id < B.id : A.x < B.A.x; }
}Q[maxn];

double nowx;
struct Line
{
	double k,b;
	int id;
	Line(double k=0,double b=0,int id=0):k(k),b(b),id(id){}
	bool operator <(const Line &B)const
	{
		double a1 = k * nowx + b , a2 = B.k * nowx + B.b;
		return dcmp3(a1-a2) == 0 ? dcmp2(k-B.k) == 0 ? id < B.id : k < B.k : a1 < a2;
	}
};

Line calc(Point a,Point b,int id)
{
	double k = (b.y-a.y)/(b.x-a.x) , B = a.y-k*a.x;
	return Line(k,B,id);
}

set<Line>st;
set<Line>::iterator it;

struct edg
{
	int x,y,w;
	edg(int x=0,int y=0,int w=0):x(x),y(y),w(w){}
	bool operator <(const edg &B)const
	{
		return w==B.w ? x==B.x ? y < B.y : x < B.x : w < B.w;
	}
}edge[maxn];

int info[maxn],Prev[maxn<<1],to[maxn<<1],cst[maxn<<1],cnt_e;
void Node(int u,int v,int ct){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=ct; }

#define lim 18
int f[lim][maxn],g[lim][maxn],dep[maxn];
void dfs(int now,int ff)
{
	dep[now] = dep[f[0][now] = ff] + 1;  
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff)
			g[0][to[i]]=cst[i],dfs(to[i],now);
}

int F[maxn];
int Find(int now){ return !F[now] ? now : F[now] = Find(F[now]); }

int solve(int a,int b)
{
	if(a == infarea  || b == infarea || Find(a)!=Find(b)) return -1;
	int ret = 0;
	if(dep[a] < dep[b]) swap(a,b);
	for(int i=0;dep[a]!=dep[b];i++)
		if((dep[a]-dep[b])>>i&1)
			ret=max(ret,g[i][a]),a=f[i][a];
	if(a == b) return ret;
	for(int i=lim-1;i>=0;i--)
		if(f[i][a]!=f[i][b])
			ret=max(ret,max(g[i][a],g[i][b])),a=f[i][a],b=f[i][b];
	ret = max(ret,max(g[0][a],g[0][b]));
	return ret;
}

set<Line>::iterator IT[maxn];

void cl(double &A)
{
	double B = round(A);
	if(B > A) A = B - 0.5;
	else A = B + 0.5;
}

int main()
{
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lf%lf",&P[i].x,&P[i].y);
	for(int i=1;i<=m;i++) 
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		u[i<<1] = a , v[i<<1] = b , h[i<<1] = c, 
		id[i<<1]=i<<1 , alp[i<<1] = atan2(P[b].y-P[a].y,P[b].x-P[a].x);
		u[i<<1|1] = b , v[i<<1|1] = a, h[i<<1|1] = c, 
		id[i<<1|1]=i<<1|1 , alp[i<<1|1] = atan2(P[a].y-P[b].y,P[a].x-P[b].x);
	}
	sort(id+2,id+2*m+2,cmp1);
	
	for(int i=2;i<=2*m+1;i++)
	{
		int p = id[i];
		rk[p] = G[u[p]].size();
		G[u[p]].push_back(p);
	}
	
	for(int i=2;i<=2*m+1;i++)
	{
		if(!bl[i])
		{
			int eid = i , x , st = u[eid];
			double area = 0;
			for(++cnt_bl;!bl[eid];)
			{
				area += (P[u[eid]] - P[st]) * (P[v[eid]] - P[st]);
				bl[eid] = cnt_bl;
				x = v[eid] , eid = eid ^ 1;
				if(rk[eid] == 0) eid = G[x].back();
				else eid = G[x][rk[eid]-1];
			}
			if(area < 0) infarea = cnt_bl;
		}
		//if(n == 50002)
		//	printf("%d\n",bl[i]);
	}
		
	for(int i=1;i<=n;i++) id[i] = i;
	sort(id+1,id+1+n,cmp2);
	
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%lf%lf",&Q[i<<1].A.x,&Q[i<<1].A.y),Q[i<<1].id=i<<1;
		scanf("%lf%lf",&Q[i<<1|1].A.x,&Q[i<<1|1].A.y),Q[i<<1|1].id=i<<1|1;
		cl(Q[i<<1].A.x);
		cl(Q[i<<1].A.y);
		cl(Q[i<<1|1].A.x);
		cl(Q[i<<1|1].A.y);
		
		//if(n == 50002)
		//{
		//	if(i == 17794) 
		//		printf("%.3lf %.3lf\n",Q[i<<1].A.x,Q[i<<1].A.y);
		//}
	}
	sort(Q+2,Q+2+2*q);
	
	nowx = P[id[1]].x;
	for(int i=2,j=1;i<=2*q+1;i++)
	{
		for(;j<=n && dcmp(Q[i].A.x-P[id[j]].x)>=0;j++) 
		{
			int x = id[j]; 
			for(int k=0,siz=G[x].size();k<siz;k++)
			{
				int eid = G[x][k];
				if(dcmp(P[u[eid]].x-P[v[eid]].x)!=0)
				{
					if(P[u[eid]].x > P[v[eid]].x)
						st.erase(IT[eid^1]);
				}
			}
			nowx = P[x].x + eps;
			for(int k=0,siz=G[x].size();k<siz;k++)
			{
				int eid = G[x][k];
				if(dcmp(P[u[eid]].x-P[v[eid]].x)!=0)
				{
					if(P[u[eid]].x < P[v[eid]].x)
						IT[eid] = st.insert(calc(P[u[eid]],P[v[eid]],eid)).first;
				}
			}
		}
		if(st.empty()){loc[Q[i].id] = infarea;continue;}
		nowx = Q[i].A.x;
		it = st.lower_bound(Line(0,Q[i].A.y,0));
		//	if(n==50002 && Q[i].id == (17794<<1))
		//		printf("%.3lf %.3lf %d\n",Q[i].A.x,Q[i].A.y,it == st.end());
		if(it == st.end()) loc[Q[i].id] = infarea;
		else if(it != st.begin()) 
		{
			it--;
			if(dcmp3((*it).k*Q[i].A.x+(*it).b - Q[i].A.y) == 0)
				loc[Q[i].id] = infarea;
			loc[Q[i].id] = bl[(*it).id];
		}
		else loc[Q[i].id] = infarea;
	}
	for(int i=1;i<=m;i++)
	{
		edge[i] = edg(bl[i<<1],bl[i<<1|1],h[i<<1]);
		//printf("%d %d %d\n",bl[i<<1],bl[i<<1|1],h[i<<1]);
	}
	sort(edge+1,edge+1+m);
	for(int i=1;i<=m;i++)
	{
		if(edge[i].x == infarea || edge[i].y == infarea) continue;
		if(Find(edge[i].x)!=Find(edge[i].y))
		{
			F[Find(edge[i].x)] = Find(edge[i].y);
			Node(edge[i].x,edge[i].y,edge[i].w);
			Node(edge[i].y,edge[i].x,edge[i].w);
		}
	}
		
	for(int i=1;i<=cnt_bl;i++)
		if(!dep[i])
			dfs(i,0);
	for(int j=1;j<lim;j++)
		for(int i=1;i<=cnt_bl;i++)
			f[j][i] = f[j-1][f[j-1][i]],
			g[j][i] = max(g[j-1][i] , g[j-1][f[j-1][i]]);

	for(int i=1;i<=q;i++)
	{
		printf("%d\n",solve(loc[i<<1],loc[i<<1|1]));
	}
}

你可能感兴趣的:(码力提高题,数据结构,图论,树,奇巧淫技)