题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=4541

题解:

平面图的对偶图,dfs树
平面图的对偶图的求法:
把所有双向边拆为两条互为反向的单向边,
显然,每条单向边应该唯一属于一个平面。
我们依次枚举还没有被确定属于哪个平面的单向边,
然后从该边出发,包裹出一个最小的平面,那么途中所经过的边都属于这个平面。
包裹的具体做法:
对于当前的边x->y,我们找到其反向边y->x顺时针旋转遇到的第一条边y->z作为包裹该平面的下一条边。
重复上述操作,直到回到起点。
然后确定了每条边属于的平面,再建立关于平面与平面之间的边。
显而易见,新建的这些边一定会与原图中的边一一对应着垂直。
所以我们尽量要使得这些新边的编号和与它垂直的边的编号对应。
建立新边的具体做法:
对于枚举到的每一条边x->y,我们得到了其所属于的平面u,并令其反向边y->v所属于的平面v ,
然后建立u->v的边,并确定其编号就为当前枚举到的边x->y的编号。
以上就是求平面图的对偶图的做法。

然后再看看本题的询问:
由于每个询问包含了很多平面,要怎样才能快速获得这些平面的信息呢。
显然由给出的点集可以得到一个由很多边围成的区域,区域里的东西就是我们所需要的平面。
做法是对所有平面,以无穷域为根,随便建立一颗dfs树,并记录子树对应的所有平面的area的和以及area2的和。
然后那些围成区域的边就会把树的一些节点给包起来,那个直接统计被包起来的点的信息就好了。
关于如何得到那些信息:
遍历那些围成区域的边,如果该边对应的与它垂直的对偶图的边在树上,
就根据该对偶图的边是朝树上还是树下去加上子树信息或减去子树信息就好了。

代码:

  1. #include<bits/stdc++.h>
  2. #define MAXN 200005
  3. #define MAXM 1200005
  4. using namespace std;
  5. struct Point{
  6. int x,y;
  7. Point(){}
  8. Point(int _x,int _y):x(_x),y(_y){}
  9. }A[MAXN];
  10. Point operator - (const Point &_A,const Point &_B){
  11. return Point(_A.x-_B.x,_A.y-_B.y);
  12. }
  13. long long operator ^ (const Point &_A,const Point &_B){
  14. return 1ll*_A.x*_B.y-1ll*_A.y*_B.x;
  15. }
  16. struct Segment{
  17. int x,y,id; double angle;
  18. Segment(){}
  19. Segment(int _x,int _y,int _id=0):x(_x),y(_y),id(_id){
  20. angle=atan2(A[y].y-A[x].y,A[y].x-A[x].x);
  21. }
  22. bool operator < (const Segment &rtm) const{
  23. return angle<rtm.angle;
  24. }
  25. }e[MAXM];
  26. vector<Segment>E[MAXN],G[MAXN*2];
  27. long long area[MAXN*2],area2[MAXN*2];
  28. int fa[MAXN*2];
  29. int bel[MAXM],nxt[MAXM];
  30. bool tag[MAXM];
  31. long long ANS1,ANS2;
  32. int N,M,K,dualroot,ent=2;
  33. void read(int &x){
  34. static int sn; static char ch;
  35. x=0; sn=1; ch=getchar();
  36. for(;ch<'0'||'9'<ch;ch=getchar()) if(ch=='-') sn=-1;
  37. for(;'0'<=ch&&ch<='9';ch=getchar()) x=x*10+ch-'0';
  38. x=x*sn;
  39. }
  40. int find(int i,Segment v){
  41. return lower_bound(E[i].begin(),E[i].end(),v)-E[i].begin();
  42. }
  43. void dfs(int u){
  44. static bool vis[MAXN*2]; vis[u]=1;
  45. for(int i=0,v;i<(int)G[u].size();i++){
  46. v=G[u][i].y;
  47. if(vis[v]) continue;
  48. fa[v]=u; tag[G[u][i].id]=tag[G[u][i].id^1]=1;
  49. dfs(v); area[u]+=area[v];
  50. area2[u]+=area2[v];
  51. }
  52. }
  53. void dualgraph(){
  54. int dnt=0;
  55. for(int i=2,st,tmp;i<ent;i++){
  56. if(bel[i]) continue;
  57. st=e[i].x; bel[i]=++dnt; tmp=i;
  58. while(1){
  59. tmp=nxt[tmp]; bel[tmp]=dnt;
  60. if(e[tmp].y==st) break;
  61. area[dnt]+=(A[e[tmp].x]-A[st])^(A[e[tmp].y]-A[st]);
  62. }
  63. if(area[dnt]<=0) dualroot=dnt;
  64. area2[dnt]=area[dnt]*area[dnt];
  65. }
  66. for(int i=2;i<ent;i++)
  67. G[bel[i]].push_back(Segment(bel[i],bel[i^1],i));
  68. }
  69. long long gcd(long long a,long long b){
  70. while(b^=a^=b^=a%=b);
  71. return a;
  72. }
  73. int decode(int x){return /*x;*/(x+ANS2)%N+1;}
  74. void solve(){
  75. long long g;
  76. static int q[MAXN];
  77. int d,u,v,p,bu,bv;
  78. while(K--){
  79. read(d); d=decode(d);
  80. for(int i=1;i<=d;i++)
  81. read(q[i]),q[i]=decode(q[i]);
  82. q[d+1]=q[1]; ANS1=ANS2=0;
  83. for(int i=1;i<=d;i++){
  84. u=q[i]; v=q[i+1];
  85. p=find(u,Segment(u,v));
  86. p=E[u][p].id;
  87. if(!tag[p]) continue;
  88. bu=bel[p]; bv=bel[p^1];
  89. if(fa[bv]==bu) ANS2-=area2[bv],ANS1-=area[bv];
  90. else ANS2+=area2[bu],ANS1+=area[bu];
  91. }
  92. if(ANS1<0) ANS1*=-1,ANS2*=-1;
  93. ANS1*=2;
  94. g=gcd(ANS2,ANS1);
  95. ANS2/=g; ANS1/=g;
  96. printf("%lld %lld\n",ANS2,ANS1);
  97. }
  98. }
  99. int main(){
  100. read(N); read(M); read(K);
  101. for(int i=1;i<=N;i++) read(A[i].x),read(A[i].y);
  102. for(int i=1,x,y;i<=M;i++){
  103. read(x); read(y);
  104. e[ent]=Segment(x,y,ent);
  105. E[x].push_back(e[ent]); ent++;
  106. e[ent]=Segment(y,x,ent);
  107. E[y].push_back(e[ent]); ent++;
  108. }
  109. for(int i=1;i<=N;i++) sort(E[i].begin(),E[i].end());
  110. for(int i=2;i<ent;i++){
  111. int p=find(e[i].y,e[i^1])-1;
  112. if(p<0) p=E[e[i].y].size()-1;
  113. nxt[i]=E[e[i].y][p].id;
  114. }
  115. dualgraph();
  116. dfs(dualroot);
  117. solve();
  118. return 0;
  119. }

  

●BZOJ 4541 [Hnoi2016]矿区的更多相关文章

  1. BZOJ 4541: [Hnoi2016]矿区 平面图转对偶图+DFS树

    4541: [Hnoi2016]矿区 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 433  Solved: 182[Submit][Status][ ...

  2. bzoj 4541: [Hnoi2016]矿区【平面图转对偶图+生成树】

    首先平面图转对偶图,大概思路是每条边存正反,每个点存出边按极角排序,然后找每条边在它到达点的出边中极角排序的下一个,这样一定是这条边所属最小多边形的临边,然后根据next边找出所有多边形,用三角剖分计 ...

  3. 4541: [Hnoi2016]矿区

    学习了一下平面图剖分的姿势,orz cbh 每次只要随便选择一条边,然后不停尽量向左转就行 #include <bits/stdc++.h> #define N 1300000 #defi ...

  4. [HNOI2016]矿区

    [HNOI2016]矿区 平面图转对偶图 方法: 1.分成正反两个单向边,每个边属于一个面 2.每个点按照极角序sort出边 3.枚举每一个边,这个边的nxt就是反边的前一个(这样找到的是面的边逆时针 ...

  5. 【LG3249】[HNOI2016]矿区

    [LG3249][HNOI2016]矿区 题面 洛谷 题解 先平面图转对偶图, 建好了对偶图之后随意拿出一个生成树,以无边界的范围为根. 无边界的范围很好求,用叉积算出有向面积时,算出来是负数的就是无 ...

  6. BZOJ 4541 【HNOI2016】 矿区

    题目链接:矿区 这道题去年暑假就想写了,但是一直拖拉,以至于现在才来写这道题.以前一直在刻意回避几何类的题目,但到了现在这个时候,已经没有什么好害怕的了. 正巧今天神犇\(xzy\)讲了这道题,那我就 ...

  7. BZOJ 4539: [Hnoi2016]树 [主席树 lca]

    4539: [Hnoi2016]树 题意:不想写.复制模板树的子树,查询两点间距离. *** 终于有一道会做的题了...... 画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在 ...

  8. BZOJ 4538: [Hnoi2016]网络 [整体二分]

    4538: [Hnoi2016]网络 题意:一棵树,支持添加一条u到v权值为k的路径,删除之前的一条路径,询问不经过点x的路径的最大权值 考虑二分 整体二分最大权值,如果\(k \in [mid+1, ...

  9. BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]

    4540: [Hnoi2016]序列 题意:询问区间所有子串的最小值的和 不强制在线当然上莫队啦 但是没想出来,因为不知道该维护当前区间的什么信息,维护前后缀最小值的话不好做 想到单调栈求一下,但是对 ...

随机推荐

  1. Beta No.7

    今天遇到的困难: 构造新适配器的时候出现了某些崩溃的问题 ListView监听器有部分的Bug 今天完成的任务: 陈甘霖:完成相机调用和图库功能,完成阿尔法项目遗留下来的位置调用问题,实现百度定位 蔡 ...

  2. Alpha冲刺Day12

    Alpha冲刺Day12 一:站立式会议 今日安排: 由黄腾飞和张梨贤继续完成政府人员模块下的风险管控子模块下的分级统计展示 由林静继续完成企业注册模块 由周静平完成登录页面模块 二:实际项目进展 人 ...

  3. Flask 学习 十四 测试

    获取代码覆盖报告 安装代码覆盖工具 pip install coverage manage.py 覆盖检测 COV = None if os.environ.get('FLASK_COVERAGE') ...

  4. JAVA_SE基础——41.instanceof关键字(运算符)

    instanceof 关键字 instanceof关键字的作用:判断一个对象是否属于指定的类别. instanceof关键字的使用前提:判断的对象与指定的类别必须要存在继承或者实现的关系.关于实现以后 ...

  5. C++ 异常小记

    catch必定使用拷贝构造函数 如下代码编译不通过,因为拷贝构造被标记delete #include <stdexcept> #include <cstdlib> #inclu ...

  6. nodeJs多进程Cluster

    在前端页面中,如果我们想进行多进程,我们会用到WebWorker,而在NodeJs中,我们如果想充分利用服务器核心资源,我们会用到Node中Cluster模块 直接上代码吧: const cluste ...

  7. linux下安装redis和phpredis扩展

    一.安装redis 1.下载redis-3.2.3.tar.gz wget http://download.redis.io/releases/redis-3.2.3.tar.gz 2.解压redis ...

  8. AJAX使用说明书

    AJAX简介 什么是AJAX AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”.即使用Javascript语言与服务器进行异 ...

  9. JMeter入门(01)概念和样例

    一.概念 JMeter 是一款专门用于功能测试和压力测试的轻量级测试开发平台,实现了许多和互联网相关的网络测试组件,同时还保留着很强的扩展性. JMeter可以用来测试诸如:静态文件,Java Ser ...

  10. Flow简易教程——安装篇

    .mydoc_h1{ margin: 0 0 1em; } .mydoc_h1_a{ color: #2c3e50; text-decoration: none; font-size: 2em; } ...