WC 2013 平面图

终于把几年前想写的这道题写了。要是了解一点相关知识的话,这题不难想但不好写。首先最左转线法抠出每个面,连接成对偶图。然后要求对偶图上任意两点的最小瓶颈路,这是MST后求倍增的经典问题。还需要nlogn的点定位算法,需要用平衡树维护竖直的扫描线上交的线段,因为两个顶点之间线段的y轴序不会发生改变。

注意一下特殊情况的处理,比如y轴平行的线段,还有连接同一端点的两条线段的顺序比较,这里用了-eps。

  1. /*
  2. Author: fffasttime
  3. Date: 2019/07/27 21:00
  4.  */
  5. #include <bits/stdc++.h>
  6. using namespace std;
  7. typedef long long ll;
  8. #define inc(i,n) for (int i=0;i<n;i++)
  9. const int N=100010;
  10. typedef double db;
  11. const db eps=1e-10;
  12. bool eq(db x){return fabs(x)<eps;}
  13. struct vec{
  14. 	db x,y;
  15. 	vec operator-(const vec &v)const{return {x-v.x,y-v.y};}
  16. 	bool operator<(const vec &v) const{return x==v.x?y<v.y:x<v.x;}
  17. 	db operator&(const vec &v)const{return x*v.y-y*v.x;}
  18. 	void rd(){scanf("%lf%lf",&x,&y);}
  19. 	db ang()const{return atan2(y,x);}
  20. }p[N*3];//p[n..n+2q] used for question
  21.  
  22. const db pi=acos(-1);
  23.  
  24. struct Edge{ //main transfer structure
  25. 	db ang; int u,v,w; bool vis;
  26. 	int rk;
  27. 	int fr;
  28. 	Edge(){}
  29. 	Edge(int u, int v, int w):u(u),v(v),w(w){
  30. 		ang=(p[v]-p[u]).ang();
  31. 		vis=0;
  32. 		rk=fr=0;
  33. 	}
  34. 	bool operator<(const Edge &v)const{return ang<v.ang;}
  35. }ed[N<<1];
  36. int edc=1,gcnt=0;
  37.  
  38. vector<int> ed1[N];
  39.  
  40. struct Ed2{
  41. 	int x,y,w;
  42. 	bool operator<(const Ed2 &v)const{
  43. 		return w<v.w;
  44. 	}
  45. }ed2[N<<1];
  46. struct Ed3{
  47. 	int to,nxt,w;
  48. }ed3[N<<1];
  49.  
  50. int h3[N],ed3c;
  51.  
  52. void add3(int x, int y, int w){
  53. 	ed3c++;
  54. 	ed3[ed3c]={y,h3[x],w};
  55. 	h3[x]=ed3c;
  56. 	ed3c++;
  57. 	ed3[ed3c]={x,h3[y],w};
  58. 	h3[y]=ed3c;
  59. }
  60.  
  61. int pa[24][N],dep[N],maxn[24][N];
  62.  
  63. int lca(int u, int v){
  64. 	int maxx=0;
  65. 	if (dep[u]<dep[v]) swap(u,v);
  66. 	for (int k=23;k>=0;k--)
  67. 		if (dep[pa[k][u]]>=dep[v]) maxx=max(maxx,maxn[k][u]),u=pa[k][u];
  68. 	if (u^v){
  69. 		for (int k=23;k>=0;k--)
  70. 			if (pa[k][u]!=pa[k][v]){
  71. 				maxx=max(maxx,max(maxn[k][u],maxn[k][v]));
  72. 				u=pa[k][u],v=pa[k][v]; 			
  73. 			}
  74. 		maxx=max(maxx,max(maxn[0][u],maxn[0][v]));
  75. 		u=pa[0][u];
  76. 	}
  77. 	return maxx;
  78. }
  79. void dfs_deep(int u, int f){
  80. 	for (int e=h3[u];e;e=ed3[e].nxt){
  81. 		int v=ed3[e].to;
  82. 		if (v^f){
  83. 			dep[v]=dep[u]+1;pa[0][v]=u;
  84. 			maxn[0][v]=ed3[e].w;
  85. 			for (int k=1;pa[k-1][pa[k-1][v]];k++)
  86. 				pa[k][v]=pa[k-1][pa[k-1][v]];
  87. 			for (int k=1;pa[k-1][pa[k-1][v]];k++)
  88. 				maxn[k][v]=max(maxn[k-1][v],maxn[k-1][pa[k-1][v]]);
  89. 			dfs_deep(v,u);
  90. 		}
  91. 	}
  92. }
  93. db curx;
  94. db liney(int li){
  95. 	int ea=ed[li].u, eb=ed[li].v;
  96. 	db rate=(curx-p[ea].x)/(p[eb].x-p[ea].x);
  97. 	return (1-rate)*p[ea].y+rate*p[eb].y;
  98. }
  99. struct DS{
  100. 	int x;
  101. 	bool operator<(const DS &v)const{
  102. 		if(x>edc) return p[x-edc-1].y-liney(v.x);
  103. 		if(v.x>edc) return liney(x)<p[v.x-edc-1].y;
  104. 		return liney(x)<liney(v.x);}
  105. };
  106. int qs[N*3],ansp[N*2];
  107. int fa[N];
  108. int fi(int x){
  109. 	if (x!=fa[x]) fa[x]=fi(fa[x]);
  110. 	return fa[x];
  111. }
  112.  
  113. int main(){
  114. 	int n,m; scanf("%d%d",&n,&m);
  115. 	inc(i,n) p[i].rd();
  116. 	inc(i,m){
  117. 		int x,y,w;
  118. 		scanf("%d%d%d",&x,&y,&w);
  119. 		x--; y--;
  120. 		ed[++edc]=Edge(x,y,w);
  121. 		ed1[x].push_back(edc);
  122. 		ed[++edc]=Edge(y,x,w);
  123. 		ed1[y].push_back(edc);
  124. 	}
  125. 	inc(i,n){
  126. 		sort(ed1[i].begin(),ed1[i].end(),[&](int a, int b){return ed[a].ang<ed[b].ang;});
  127. 		inc(j,ed1[i].size())
  128. 			ed[ed1[i][j]].rk=j;
  129. 	}
  130. 	int gout;
  131. 	for (int i=2;i<=edc;i++) if(!ed[i].vis){ //new
  132. 		int u=ed[i].u; int cur=i;
  133. 		gcnt++;
  134. 		db area=0;
  135. 		while (!ed[cur].vis){ //face
  136. 			ed[cur].fr=gcnt;
  137. 			ed[cur].vis=1;
  138. 			area+=(p[ed[cur].u]-p[u])&(p[ed[cur].v]-p[u]);
  139. 			int sz=ed1[ed[cur].v].size();
  140. 			int rk1=(ed[cur^1].rk-1+sz)%sz;
  141. 			cur=ed1[ed[cur].v][rk1];
  142. 		}
  143. 		if (area<0) gout=gcnt;
  144. 	}
  145. 	int ed2c=0;
  146. 	for (int i=2;i<=edc;i++) if(ed[i].fr!=gout && ed[i^1].fr!=gout) ed2[ed2c++]={ed[i].fr,ed[i^1].fr,ed[i].w}; //kruskal edge
  147. 	sort(ed2,ed2+ed2c);
  148. 	for (int i=1;i<=gcnt;i++) fa[i]=i;
  149. 	for (int i=0;i<ed2c;i++){
  150. 		int ta=fi(ed2[i].x),tb=fi(ed2[i].y);
  151. 		if (ta^tb) add3(ed2[i].x,ed2[i].y,ed2[i].w),fa[ta]=tb;
  152. 	}
  153. 	dep[1]=1; dfs_deep(1,0);
  154. 	int q; scanf("%d",&q);
  155. 	for (int i=0;i<q;i++){p[i*2+n].rd();p[i*2+1+n].rd();} 
  156. 	inc(i,n+q*2) qs[i]=i; //sort by x-axis
  157. 	sort(qs,qs+n+q*2,[&](int a, int b){return p[a]<p[b];});
  158. 	reverse(qs,qs+n+q*2);
  159. 	set<DS> se;
  160. 	inc(i,n+q*2){
  161. 		int u=qs[i];
  162. 		curx=p[u].x;
  163. 		if (u<n){
  164. 			curx=p[u].x+0.1;
  165. 			for(auto e:ed1[u]){ 
  166. 				if (eq(ed[e].ang-pi/2) || eq(ed[e].ang+pi/2)) continue;
  167. 				if (ed[e].ang<pi/2 && ed[e].ang>-pi/2)
  168. 					se.erase((DS){e^1});
  169. 			}
  170. 			curx=p[u].x-0.1;
  171. 			for(auto e:ed1[u]){
  172. 				if (eq(ed[e].ang-pi/2) || eq(ed[e].ang+pi/2)) continue;
  173. 				if (ed[e].ang>pi/2 || ed[e].ang<-pi/2)
  174. 					se.insert((DS){e});
  175. 			}
  176. 		}
  177. 		else{
  178. 			int fr;
  179. 			auto it=se.lower_bound((DS){u+edc+1});
  180. 			if (se.empty() || it==se.end()) fr=gout;
  181. 			else fr=ed[it->x].fr;
  182. 			ansp[u-n]=fr;
  183. 		}
  184. 	}
  185. 	for(int i=0;i<q;i++){
  186. 		//printf("%d %d\n",ansp[i<<1],ansp[i<<1|1]);
  187. 		if (ansp[i*2]==gout || ansp[i*2+1]==gout) puts("-1");
  188. 		else printf("%d\n",lca(ansp[i*2],ansp[i*2+1]));
  189. 	}
  190. 	return 0;
  191. }

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注