简要题意:二维平面上n个点,点之间有一些连线,连线不在点之外的地方相交,将平面分为若干个区域。给出一些询问点对,问从这个点所在的区域走到另一个点所在的区域的最小代价。

题解:这道题首先可以把平面图转对偶图,这一点比较容易发现。然后对于从左指向右的线段,运用扫描线的思想,扫到左端点加入平衡树,扫到右端点从平衡树中删除。因为两线互不相交,所以相对位置不变。然后建立平面直角坐标系,y轴可以随意左右平移。对于每一条线段,我们使右端点正好在y轴上,然后选择两线段左端点x坐标比较大的作为比较直线,计算这条直线与两线段的交点的高低。然后就是一堆细节。真实的码农题。我写了3个namespace不然受不了

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e5+,inf=1e9;
  4. const double eps=1e-;
  5. int n,m,q,num,bel[N<<];
  6. struct edge{int v,nxt,w,id;}e[N<<];
  7. struct Edge{int u,v,w;double o;}d[N<<];
  8. struct point{
  9. int x,y,id;
  10. void init(int i)
  11. {
  12. double xx,yy;scanf("%lf%lf",&xx,&yy);
  13. x=(int)(xx*+eps),y=(int)(yy*+eps),id=i;
  14. }
  15. }p[N],Q[N<<];
  16. struct node{int x,y,t;};
  17. bool operator<(node a,node b){return a.x!=b.x?a.x<b.x:a.t<b.t;}
  18. namespace MST{
  19. int cnt,ecnt,f[N],hd[N],fa[N][],d[N][],dep[N];
  20. Edge E[N<<];
  21. edge e2[N<<];
  22. void adde(int x,int y,int z)
  23. {
  24. e2[++ecnt]=(edge){y,hd[x],z},hd[x]=ecnt;
  25. e2[++ecnt]=(edge){x,hd[y],z},hd[y]=ecnt;
  26. }
  27. int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
  28. bool cmp(Edge a,Edge b){return a.w<b.w;}
  29. void add(int u,int v,int w){E[++cnt]=(Edge){u,v,w};}
  30. void dfs(int x)
  31. {
  32. for(int i=;i<=;i++)
  33. {
  34. fa[x][i]=fa[fa[x][i-]][i-];
  35. d[x][i]=max(d[x][i-],d[fa[x][i-]][i-]);
  36. }
  37. for(int i=hd[x];i;i=e2[i].nxt)
  38. if(e2[i].v!=fa[x][])
  39. dep[e2[i].v]=dep[x]+,fa[e2[i].v][]=x,d[e2[i].v][]=e2[i].w,dfs(e2[i].v);
  40. }
  41. int lca(int x,int y)
  42. {
  43. if(dep[x]<dep[y])swap(x,y);
  44. int ret=,t=dep[x]-dep[y];
  45. for(int i=;(<<i)<=t;i++)if(t&(<<i))ret=max(ret,d[x][i]),x=fa[x][i];
  46. if(x==y)return ret;
  47. for(int i=;~i;i--)
  48. if(fa[x][i]!=fa[y][i])ret=max(ret,max(d[x][i],d[y][i])),x=fa[x][i],y=fa[y][i];
  49. return max(ret,max(d[x][],d[y][]));
  50. }
  51. void work()
  52. {
  53. sort(E+,E+cnt+,cmp);
  54. for(int i=;i<=num;i++)f[i]=i;
  55. for(int i=;i<=cnt;i++)
  56. {
  57. int x=find(E[i].u),y=find(E[i].v);
  58. if(x!=y)adde(E[i].u,E[i].v,E[i].w),f[x]=y;
  59. }
  60. dfs();
  61. for(int i=;i<=q;i++)
  62. {
  63. if(bel[i]==||bel[i+q]==){puts("-1");continue;}
  64. int ans=lca(bel[i],bel[i+q]);
  65. if(ans==inf)puts("-1");else printf("%d\n",ans);
  66. }
  67. }
  68. }
  69. namespace ScanLine{
  70. struct cmp{
  71. bool operator()(int i,int j)
  72. {
  73. if(d[i].u==d[j].u)return d[i].o>d[j].o;
  74. int x=max(p[d[i].u].x,p[d[j].u].x);
  75. double x1=1.0*(p[d[i].v].y-p[d[i].u].y)*(x-p[d[i].v].x)/(p[d[i].v].x-p[d[i].u].x)+p[d[i].v].y;
  76. double x2=1.0*(p[d[j].v].y-p[d[j].u].y)*(x-p[d[j].v].x)/(p[d[j].v].x-p[d[j].u].x)+p[d[j].v].y;
  77. return x1>x2;
  78. }
  79. };
  80. set<int,cmp>S;
  81. node a[N<<];
  82. int cnt=;
  83. void work()
  84. {
  85. for(int i=;i<=(m<<)+;i++)
  86. if(p[d[i].u].x<p[d[i].v].x)a[++cnt]=(node){p[d[i].u].x,i,},a[++cnt]=(node){p[d[i].v].x,i,};
  87. for(int i=;i<=q;i++)a[++cnt]=(node){Q[i].x,i,},a[++cnt]=(node){Q[i+q].x,i+q,};
  88. sort(a+,a+cnt+);
  89. for(int i=;i<=cnt;i++)
  90. if(!a[i].t)S.erase(a[i].y);
  91. else if(a[i].t==)S.insert(a[i].y);
  92. else{
  93. p[n+]=(point){a[i].x,Q[a[i].y].y,};
  94. p[n+]=(point){a[i].x-,Q[a[i].y].y,};
  95. d[(m<<)+]=(Edge){n+,n+,,atan2(p[n+].y-p[n+].y,p[n+].x-p[n+].x)};
  96. S.insert((m<<)+);
  97. set<int,cmp>::iterator it=S.find((m<<)+);
  98. if(it!=S.begin())bel[a[i].y]=e[*--it].id;else bel[a[i].y]=;
  99. S.erase((m<<)+);
  100. }
  101. }
  102. }
  103. namespace Graph{
  104. int cnt=,hd[N],nxt[N<<];
  105. vector<pair<double,int> >G[N];
  106. point s=(point){inf,inf,};
  107. void adde(int x,int y,int z)
  108. {
  109. e[++cnt]=(edge){y,hd[x],z,-},hd[x]=cnt;
  110. e[++cnt]=(edge){x,hd[y],z,-},hd[y]=cnt;
  111. }
  112. void dosort(int x)
  113. {
  114. for(int i=hd[x];i;i=e[i].nxt)
  115. G[x].push_back(make_pair(atan2(p[e[i].v].y-p[x].y,p[e[i].v].x-p[x].x),i));
  116. sort(G[x].begin(),G[x].end());
  117. int sz=G[x].size();
  118. for(int i=;i<sz;i++)nxt[G[x][i].second^]=G[x][(i+)%sz].second;
  119. }
  120. void find(int x){for(int i=x;e[i].id<;i=nxt[i])e[i].id=num;}
  121. void work()
  122. {
  123. cnt=;
  124. for(int i=;i<=n;i++)
  125. {
  126. p[i].init(i);
  127. if(s.x>p[i].x||s.x==p[i].x&&s.y>p[i].y)s=p[i];
  128. }
  129. for(int i=,x,y,z;i<=m;i++)
  130. {
  131. scanf("%d%d%d",&x,&y,&z);
  132. d[i<<]=(Edge){x,y,z,atan2(p[y].y-p[x].y,p[y].x-p[x].x)};
  133. d[(i<<)+]=(Edge){y,x,z,atan2(p[x].y-p[y].y,p[x].x-p[y].x)};
  134. adde(x,y,z);
  135. }
  136. scanf("%d",&q);
  137. for(int i=;i<=q;i++)Q[i].init(i),Q[i+q].init(i+q);
  138. for(int i=;i<=n;i++)dosort(i);
  139. num=;
  140. find(G[s.id][].second);
  141. for(int i=;i<=cnt;i++)if(e[i].id<)++num,find(i);
  142. for (int i=;i<=cnt;i+=)
  143. if(e[i].id!=&&e[i^].id!=)MST::add(e[i].id,e[i^].id,e[i].w);
  144. else MST::add(e[i].id,e[i^].id,inf);
  145. }
  146. }
  147. int main()
  148. {
  149. scanf("%d%d",&n,&m);
  150. Graph::work();
  151. ScanLine::work();
  152. MST::work();
  153. }

bzoj3051[WC2013]平面图(树上倍增+平面图转对偶图+扫描线)的更多相关文章

  1. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  2. NOIP2013 货车运输 (最大生成树+树上倍增LCA)

    死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...

  3. HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...

  4. [NOIP2013/Codevs3287]货车运输-最小[大]生成树-树上倍增

    Problem 树上倍增 题目大意 给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大. Solution 看到这个题第一反应是图论.. 然而,任意路径最小的边权值最大,如 ...

  5. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  6. [树上倍增+二分答案][NOIP2012]运输计划

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 公元 2044 年,人类进入了宇宙纪元 L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n− ...

  7. 两种lca的求法:树上倍增,tarjan

    第一种:树上倍增 f[x,k]表示x的2^k辈祖先,即x向根结点走2^k步达到的结点. 初始条件:f[x][0]=fa[x] 递推式:f[x][k]=f[ f[x][k-1] ][k-1] 一次bfs ...

  8. 【NOIP2013/Codevs3287】货车运输-最小生成树(大)-树上倍增

    https://www.luogu.org/problemnew/show/P1967 由题可知,我们走的路的边应尽可能大,所以通过kruscal建最大生成树的图,再树上倍增,注意可能有多棵树; #i ...

  9. LCA树上倍增

    LCA就是最近公共祖先,比如 节点10和11的LCA就是8,9和3的LCA就是3. 我们这里讲一下用树上倍增来求LCA. 大家都可以写出暴力解法,两个节点依次一步一步往上爬,直到爬到了相同的一个节点. ...

随机推荐

  1. Docker: 企业级镜像仓库Harbor部署(http)

    Harbor离线安装包下载地址:https://github.com/goharbor/harbor Docker compose(安装harbor需要用到docker compose)下载地址:ht ...

  2. Vim 宏

    宏的概念 什么是宏呢?英文名:macro,代表一串命令的集合. 示例操作文本 SELECT * FROM `edu_ocr_task` WHERE ((`userId`=284871) AND (`u ...

  3. Python开发【内置模块篇】configparser

    生成配置文件 import configparser config = configparser.ConfigParser() config[', 'Compression': 'yes', ', ' ...

  4. idea spring-boot总结

    1. 按自己重新配置spring-boot pom点进 mybatis-spring-boot-starter ,在要改的里面 <version>3.4.4</version> ...

  5. day4-python基础-数据类型

    今日份小技巧 a =3 b=4, 最快将a和b值替换的方法为 a,b =b,a 今日内容 1. 字典 2. 集合 3.hash 4.基本数据类型总结 5.循环之for循环 6.range的使用 7.深 ...

  6. 迷茫<第三篇:再到北京>

    这是2016年初春,三月的北京仍带着丝丝的冷意,我再次来到了这座熟悉又陌生的城市.我是早上6点钟到的北京西站,坐火车过来的,一夜未眠,眼睛很疲劳.这次过来和上次回长沙一样,下了火车先把行李寄存在朋友家 ...

  7. SpringBoot系列十:SpringBoot整合Redis

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合 Redis 2.背景 Redis 的数据库的整合在 java 里面提供的官方工具包:jed ...

  8. Linux利用mysql建立数据库

    安装数据库: sudo   apt-get  install  mysql-server   启动服务: sudo  service  mysql  start  连接数据库:sudo    mysq ...

  9. Kubernetes一键部署利器:kubeadm

    要真正发挥容器技术的实力,你就不能仅仅局限于对 Linux 容器本身的钻研和使用. 这些知识更适合作为你的技术储备,以便在需要的时候可以帮你更快的定位问题,并解决问题. 而更深入的学习容器技术的关键在 ...

  10. 给hMailServer添加DKIM图文教程

    https://www.hmailserver.org/viewtopic.php?f=4&t=12