本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

Description

  平面上的矿区划分成了若干个开发区域。简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若
干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点
的线段组成。每个开发区域的矿量与该开发区域的面积有关:具体而言,面积为s的开发区域的矿量为 s^2。现在
有 m 个开采计划。每个开采计划都指定了一个由若干开发区域组成的多边形,一个开采计划的优先度被规定为矿
量的总和÷开发区域的面积和;例如,若某开采计划指定两个开发区域,面积分别为 a和b,则优先度为(a^2+b^2)
/(a+b)。由于平面图是按照划分开发区域边界的点和边给出的,因此每个开采计划也只说明了其指定多边形的边界
,并未详细指明是哪些开发区域(但很明显,只要给出了多边形的边界就可以求出是些开发区域)。你的任务是求
出每个开采计划的优先度。为了避免精度问题,你的答案必须按照分数的格式输出,即求出分子和分母,且必须是
最简形式(分子和分母都为整数,而且都消除了最大公约数;例如,若矿量总和是 1.5,面积和是2,那么分子应
为3,分母应为4;又如,若矿量和是 2,面积和是 4,那么分子应为 1,分母应为 2)。由于某些原因,你必须依
次对每个开采计划求解(即下一个开采计划会按一定格式加密,加密的方式与上一个开采计划的答案有关)。具体
的加密方式见输入格式。

Input

  第一行三个正整数 n,m,k,分别描述平面图中的点和边,以及开采计划的个数。接下来n行,第 i行(i=1,2,…
,n)有两个整数x_i, y_i,  表示点i的坐标为(x_i, y_i)。接下来m行,第 i行有两个正整数a,b,表示点a和b 之间
有一条边。接下来一行若干个整数,依次描述每个开采计划。每个开采计划的第一个数c指出该开采计划由开发区
域组成的多边形边界上的点的个数为d=(c+P) mod n + 1;接下来d个整数,按逆时针方向描述边界上的每一个点:
设其中第i个数为z_i,则第i个点的编号为(z_i+P) mod n + 1。其中P 是上一个开采计划的答案中分子的值;对于
第 1 个开采计划,P=0。

Output

  对于每个开采计划,输出一行两个正整数,分别描述分子和分母。

Sample Input

9 14 5
0 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
1 2
2 3
5 6
7 8
8 9
1 4
4 7
5 8
3 6
6 9
4 8
1 5
2 6
6 8
3 3 0 4 7 1 3 4 6 4 8 0 4 3 6 2 3 8 0 4 6 2 5 0 4 5 7 6 3

Sample Output

1 1
1 2
1 1
9 10
3 4

HINT

输入文件给出的9个点和14条边描述的平面图如下所示:

第一个开采计划,输入的第1个值为3,所以该开采计

划对应的多边形有(3+0) mod 8 +1=4个点,将接下的4个数3,0,4,7,分别代入(z_i+0) mod n + 1得到4个点的编号

为4,1,5,8。计算出第一个开采计划的分子为1,分母为1。类似地,可计算出余下开采计划的多边形的点数和点的

编号:第二个开采计划对应的多边形有3个点,编号分别为5, 6, 8。第三个开采计划对应的多边形有6个点,编号

分别为1, 2, 6, 5, 8, 4。第四个开采计划对应的多边形有5个点,编号分别为1, 2, 6, 8, 4。第五个开采计划对

应的多边形有6个点,编号分别为1, 5, 6, 8, 7, 4。

对于100%的数据,n, k ≤ 2×10^5, m ≤ 3n-6, |x_i|, |y

_i| ≤ 3×10^4。所有开采计划的d之和不超过2×10^6。保证任何开采计划都包含至少一个开发区域,且这些开发

区域构成一个连通块。保证所有开发区域的矿量和不超过 2^63-1。保证平面图中没有多余的点和边。保证数据合

法。由于输入数据量较大,建议使用读入优化。

正解:平面图转对偶图+树上统计

解题报告:

  这是我做的第一道计算几何大神题呀…

  考虑先把原图转成对偶图,转的方式就是,把无向边拆成两条有向边,然后对于每个点把他的所有出边极角排序,用vector的话很方便。

  然后我们就可以对于每条边算出从他出发的下一条要走的边是哪一条,二分预处理一下,记录下来。

  接下来就是扣域了!

  我从每一条没有归属的边出发,一路往下走,直到回到这条边的起点,把每条边标记为同一个域,我们可以在图上画画就能发现,扣出来的一定是这些边围出来的域。

  至于每次的下一条边,是极角序变大还是变小,就看你的定义了,其实是等价的。

  需要注意的是,我要用叉积顺便算一下每个域的面积,而面积为负数的域就是无穷域。

  然后我令无穷域为根节点,dfs一遍所有域,得到一棵对偶图的生成树,标记一下树边,并且统计子树的面积和以及面积平方和。

  对于每次询问,我只需要用像最开始找下一条边的方式找出相邻两个点之间的边的编号,如果是非树边就直接忽略,否则计算一下这条边所代表的儿子节点中的子树贡献。

  我们不妨规定一个方向,如果这条边时正方向就加上贡献,否则就减去,当然最后要取绝对值。

  

  我也不会证明呀...似乎可以用反证法来考虑,感觉一下还是可以意会的...

  有一个小trick:考虑我们叉积算出来的面积是四边形面积,本应该要/2,但是有可能会出现小数,所以我们先上下同时乘4就可以避免这个问题了...

//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 200011;
const int MAXM = 1200011;
int n,m,k,ecnt,next[MAXM],rt,belong[MAXM],cnt,father[MAXM]/*!!!*/,ask[MAXN];
bool vis[MAXM],in[MAXM];
LL s[MAXM],sp[MAXM],P,Q;
struct point{
int x,y;
inline point operator - (const point a) const { return (point){x-a.x,y-a.y}; }//向量,末-初
inline LL operator * (const point a) const { return 1LL*x*a.y-1LL*y*a.x; }//叉积
}p[MAXM]; struct edge{
int u,v,id;
double ang;
edge(){}
edge(int a,int b,int ii){ u=a; v=b; id=ii; ang=atan2(p[b].y-p[a].y,p[b].x-p[a].x); }
inline bool operator < (const edge a) const { return a.ang>ang; }
}e[MAXM]; vector<edge>w[MAXN],Tree[MAXM]; inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline void link(int x,int y){ ecnt++; e[ecnt]=edge(x,y,ecnt); w[x].push_back(e[ecnt]); } inline LL gcd(LL x,LL y){ if(y==0) return x; return gcd(y,x%y); } inline int find(int x,const edge &bian){
int l=0,r=w[x].size()-1,mid;
while(l<r) {
mid=(l+r+1)>>1;/*!!!二分的方式*/
if(bian<w[x][mid]) r=mid-1;
else l=mid;
}
return l;
} inline void dfs(int x){
vis[x]=1;
sp[x]=s[x]*s[x]; s[x]<<=1;//考虑我们叉积算出来的面积是四边形面积,本应该要/2,但是有可能会出现小数,所以我们先上下同时乘4就可以避免这个问题了
for(int i=0,ss=Tree[x].size();i<ss;i++) {
int v=Tree[x][i].v; if(vis[v]) continue;
father[v]=x; in[Tree[x][i].id]=in[Tree[x][i].id^1]=1;//标记为树边
dfs(v); s[x]+=s[v]; sp[x]+=sp[v];//统计子树面积和,以及子树面积的平方和
}
} inline void work() {
n=getint(); m=getint(); k=getint();
ecnt=1; int x,y,nex;
for(int i=1;i<=n;i++) x=getint(),y=getint(),p[i]=(point){x,y};
for(int i=1;i<=m;i++) x=getint(),y=getint(),link(x,y),link(y,x);
for(int i=1;i<=n;i++) sort(w[i].begin(),w[i].end());//把每个点的出边按极角排序
for(int i=2;i<=ecnt;i++) {//预处理出每条边的反向边的极角序的下一条边,即走完这条边之后要走的下一条边
nex=find(e[i].v,e[i^1])-1;
if(nex==-1) nex=w[e[i].v].size()-1;//转一圈转了回来
next[i]=w[e[i].v][nex].id;//这条边走出去的下一条边
} for(int i=2;i<=ecnt;i++) {//处理每条边属于哪个域
if(!belong[i]) {
belong[i]=belong[next[i]]=++cnt;
for(int now=next[i];e[now].v!=e[i].u;now=next[now],belong[now]=cnt) {//直到回到原点
s[cnt]+=(p[e[now].u]-p[e[i].u])*(p[e[now].v]-p[e[i].u]);//叉积算面积,注意后者位于前者的逆时针方向才为正
}
if(s[cnt]<=0) rt=cnt;//无穷域
}
} for(int i=2;i<=ecnt;i++) Tree[belong[i]].push_back(edge(belong[i],belong[i^1],i));
dfs(rt); int d,now; P=Q=0;
while(k--) {
d=(getint()+P)%n+1;
for(int i=1;i<=d;i++) ask[i]=(getint()+P)%n+1;
ask[d+1]=ask[1]; P=Q=0;
for(int i=1;i<=d;i++) {
now=w[ask[i]][ find(ask[i],edge(ask[i],ask[i+1],0)) ].id;//找到当前边中的下一条边
if(!in[now]) continue;//考虑这条边在对偶图中的对应边,如果是非树边则不用考虑
if(father[belong[now]] == belong[now^1]) Q+=s[belong[now]],P+=sp[belong[now]];//考虑子树的统计,规定方向后,则只需对子树进行加加减减操作即可
else Q-=s[belong[now^1]],P-=sp[belong[now^1]];
}
LL gg=gcd(P,Q);
//LL gg=__gcd(P,Q);
P/=gg; Q/=gg;
printf("%lld %lld\n",P,Q);
}
//cout<<clock()<<endl;
} int main()
{
work();
return 0;
}

  

BZOJ4541 [Hnoi2016]矿区的更多相关文章

  1. BZOJ4541 HNOI2016矿区(平面图转对偶图)

    考虑先将平面图转化为对偶图.具体地,将无向边拆成两条有向边.每次考虑找到包围一个区域的所有边.对当前考虑的边,找到该边的反向边在该边终点的出边集中,按极角序排序的后继,这条后继边也是包围该区域的边.这 ...

  2. [BZOJ4541][HNOI2016]矿区(平面图转对偶图)

    https://www.cnblogs.com/ljh2000-jump/p/6423399.html #include<cmath> #include<vector> #in ...

  3. [HNOI2016]矿区

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

  4. 【LG3249】[HNOI2016]矿区

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

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

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

  6. 【bzoj4541】 Hnoi2016—矿区

    http://www.lydsy.com/JudgeOnline/problem.php?id=4541 (题目链接) 题意 给出一个平面图,若干询问,每次询问一个凸多边形内小多边形面积的平方和与面积 ...

  7. 4541: [Hnoi2016]矿区

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

  8. ●BZOJ 4541 [Hnoi2016]矿区

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4541 题解: 平面图的对偶图,dfs树 平面图的对偶图的求法: 把所有双向边拆为两条互为反向 ...

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

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

随机推荐

  1. Java基础-SSM之mybatis多对多关联

    Java基础-SSM之mybatis多对多关联 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.准备测试环境(创建数据库表) 1>.创建teas,stus,links表 u ...

  2. Spark记录-spark与storm比对与选型(转载)

    大数据实时处理平台市场上产品众多,本文着重讨论spark与storm的比对,最后结合适用场景进行选型. 一.spark与storm的比较 比较点 Storm Spark Streaming 实时计算模 ...

  3. SQL记录-Linux CentOS配置ORACLE 12c

    1.准备LIINX软件包 操作系统:centos7 虚拟机:VMware 12 JDK:1.8 数据库:oracle 12c 2.配置基础环境 2.1 部署虚拟机VM(过程略) 2.2 部署操作系统C ...

  4. bzoj千题计划256:bzoj2194: 快速傅立叶之二

    http://www.lydsy.com/JudgeOnline/problem.php?id=2194 相乘两项的下标 的 差相同 那么把某一个反过来就是卷积形式 fft优化 #include< ...

  5. jQuery总结或者锋利的jQuery笔记一

      在线测试脚本网站 层次 选择器要多花时间看看. 第一章: hover = enter+leave jQuery对象 jQuery产生的对象时jQuery独有的,只能自己调用 var $c=$(&q ...

  6. ASP.NET MVC学习(五)之MVC原理解析

    ASP.NET MVC 请求生命周期 生命周期步骤概览 当我们对ASP.NET MVC网站发出一个请求的时候,会发生5个主要步骤: 步骤1:创建RouteTable 当ASP.NET应用程序第一次启动 ...

  7. 【ORACLE】oracl基本操作笔记

    1.用命令导入导出表 C:\Users\xiang>imp bjlims/bjlims@orcl file="c:\tjlims.dmp" full=y C:\Users\x ...

  8. 为什么mysqlbinlog --database选项不起作用

    群里看到有同学提问,多瞅了眼 [root@mysql55 mysql]# mysqlbinlog --no-defaults -vv --base64-output=decode-rows mysql ...

  9. mybatis一对一关联查询——(八)

    1.需求 查询所有订单信息,关联查询下单用户信息. 注意: 因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询.如果从用户信息出发查询用户下的订单信息则为一对多查 ...

  10. imperva—waf 敏感字段显现

    imperva WAF中看到的日志内容信息有些都是敏感的  比如登录登出的信息 如何调整敏感信息的现实方式,并可以自定义敏感字段? 这里添加字段就可以了 这样就将******转变为明文了