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

时间:2022-09-24 13:53:50

4541: [Hnoi2016]矿区

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 433  Solved: 182
[Submit][Status][Discuss]

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条边描述的平面图如下所示:

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

第一个开采计划,输入的第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。保证平面图中没有多余的点和边。保证数据合

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

Source

题意:一个开采计划优先度为$\frac{\sum S^2(X)}{\sum S(X)}$其中X∈A,S(x)为开发区域的面积。

想法:将原平面图G转对偶图G'后,一个域被算入的条件就是不与外面的无穷域Rt连通。如果以无穷域为根,DFS遍历得到的树T。然后可以想象一下,一个域被算进来,就是他被割下了,就是划开一个连通块,树上多个连通块组成开采计划。

具体过程:

1.平面图G转对偶图G’。(不会戳这里)

2.DFS遍历图G‘得到树T,每个节点维护$S(x)$,$S^2(x)$子树和

3.回答询问。对于有向边(u->v),先找到其在G'中对应的上下域(a,b)。如果(a,b)是非树边,那么就可以忽略,毕竟不会影响答案统计。是树边,就要分情况累加答案。

先分析一下:假设(u->v)方向的都割掉连通块与叶子节点通路上的边,那么就肯定是减去b的子树和,反之加上a的子树和。如果(u->v)的不是,答案便要取反。所以这样统计是可行的。判断条件:a是不是b的父亲。

总复杂度$O(M\log M+\sum d)$

#include< algorithm>
#include< cmath >
#include< cstdio >
#include< vector > #define gec getchar
#define FILE(F) freopen(F".in","r",stdin),freopen(F".out","w",stdout)
#define DEBUG fprintf(stderr,"Passing [%s] in Line (%d)\n",__FUNCTION__,__LINE__); typedef long long ll;
template
inline void read(T&x)
{
x=0;bool f=0;char c=gec();
for(;c<'0'||c>'9';c=gec())f=(c=='-');
for(;c>='0'&&c<='9';c=gec())x=x*10+c-'0';
x=f?-x:x;
}
const int MAXN(200010),MAXM(600010);
int n,m,k,a,b;ll P,Q;
struct Coor
{
int x,y;
Coor(){};
Coor(int a,int b):x(a),y(b){};
inline Coor operator +(const Coor&A){return Coor(x+A.x,y+A.y);}
inline Coor operator -(const Coor&A){return Coor(x-A.x,y-A.y);}
inline Coor operator *(const double k){return Coor(k*x,k*y);}
inline Coor operator /(const double k){return Coor(x/k,y/k);}
}PA[MAXN];
ll acorss(Coor A,Coor B)
{return (ll)A.x*B.y-(ll)A.y*B.x;}
ll dot(Coor A,Coor B)
{return (ll)A.x*B.x+(ll)A.y*B.y;}
//===================================================计算几何
struct Next
{
int u,v,id;double ang;
Next(){}
Next(int a,int b,int k)
{u=a; v=b; id=k; ang=atan2(PA[u].x-PA[v].x,PA[u].y-PA[v].y);}
inline bool operator <(const Next &A)const {return ang<A.ang;}
}e[MAXM<<1];
std::vectorEdge[MAXN];
int cnt=1,Nex[MAXM<<1],col[MAXM<<1];bool flag[MAXM<<1];
int etot,rt;ll S[MAXN<<1],Sp[MAXN<<1];
struct Node{int nd,nx;}bot[MAXM<<1];
int tot=1,first[MAXN<<1],fa[MAXN<<1];bool vis[MAXN<<1];//F-E+V=2
void add(int a,int b)
{bot[++tot]=(Node){b,first[a]};first[a]=tot;}
namespace planar_graph
{
int Two_Find(int num,Next &x)
{
int l=0,r=Edge[num].size()-1,mid,Ans;
for(;l<=r;)if(x<Edge[num][mid=(l+r)>>1])r=mid-1;else l=mid+1,Ans=mid;
return Ans;
}
void Get_planar()
{
for(int i=2;i<=cnt;i++)
if(!col[i])
{
int now=i;col[i]=++etot;ll tmp_s=0;
for(;;)
{
now=Nex[now];col[now]=etot;
if(e[now].v==e[i].u)break;//成环
tmp_s+=acorss(PA[e[now].v]-PA[e[i].u],PA[e[now].u]-PA[e[i].u]);
}
S[etot]=tmp_s;
if(tmp_s<=0)rt=etot;//无穷域
}
for(int i=2;i<=cnt;i++)
add(col[i],col[i^1]);//相邻域连边
}
void build()
{
for(int i=1;i<=m;i++)
{
read(a);read(b);
++cnt;e[cnt]=Next(a,b,cnt);
Edge[a].push_back(e[cnt]);
++cnt;e[cnt]=Next(b,a,cnt);
Edge[b].push_back(e[cnt]);
}
for(int i=1;i<=n;i++)
std::sort(Edge[i].begin(),Edge[i].end());
for(int i=2;i<=cnt;i++)
{
Nex[i]=Two_Find(e[i].v,e[i^1])-1;
if(Nex[i]<0)Nex[i]=Edge[e[i].v].size()-1;
Nex[i]=Edge[e[i].v][Nex[i]].id;
}//找下一条边
Get_planar();
}
}
//===================================================平面图转对偶图
namespace WW_HASH
{
const int MP(980321),HM(233333);
int nx[MAXM<<1],head[MP];
void build_HASH()
{
for(int i=2,v;i<=cnt;i++)
{
v=((ll)e[i].u*HM%MP+e[i].v)%MP;
nx[i]=head[v];head[v]=i;
}
}
int Find(int a,int b)
{
int v=((ll)a*HM%MP+b)%MP;
for(v=head[v];v;v=nx[v])
if(e[v].u==a&&e[v].v==b)return v;
exit(0);//不存在的
}
}
void Dfs(int x)
{
vis[x]=1; Sp[x]=S[x]*S[x]; S[x]<<=1;
for(int v=first[x];v;v=bot[v].nx)
if(!vis[bot[v].nd])
{
fa[bot[v].nd]=x;
flag[v]=flag[v^1]=1;
Dfs(bot[v].nd);
S[x]+=S[bot[v].nd];
Sp[x]+=Sp[bot[v].nd];
}
}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
const int SUMD(2000010);
int d,z[SUMD];
int main()
{
#ifndef ONLINE_JUDGE
FILE("C");
#endif
read(n);read(m);read(k);
for(int i=1;i<=n;i++)
read(PA[i].x),read(PA[i].y);
planar_graph::build();
WW_HASH::build_HASH(); Dfs(rt);
// DEBUG;
for(int i=1;i<=k;i++)
{
read(d);d=(d+P)%n +1;
for(int j=1;j<=d;j++)
read(z[j]),z[j]=(z[j]+P)%n +1;
z[0]=z[d];
P=Q=0;
for(int j=1,id;j<=d;j++)
{
id=WW_HASH::Find(z[j-1],z[j]);
// fprintf(stderr,"id:%d\n",id);
if(!flag[id])continue;//非树边
if(fa[col[id]]==col[id^1])
P-=Sp[col[id]],Q-=S[col[id]]; else
P+=Sp[col[id^1]],Q+=S[col[id^1]];
// fprintf(stderr,"%lld %lld\n",P,Q);
}
if(P<0)P=-P,Q=-Q;
// DEBUG;
// fprintf(stderr,"%lld %lld\n",P,Q);
ll g=gcd(P,Q);P/=g;Q/=g;
printf("%lld %lld\n",P,Q);
}
//DEBUG;
return 0;
}
														
		

BZOJ 4541: [Hnoi2016]矿区 平面图转对偶图+DFS树的更多相关文章

  1. ●BZOJ 4541 &lbrack;Hnoi2016&rsqb;矿区

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

  2. bzoj 4541&colon; &lbrack;Hnoi2016&rsqb;矿区【平面图转对偶图&plus;生成树】

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

  3. &lbrack;BZOJ4541&rsqb;&lbrack;HNOI2016&rsqb;矿区&lpar;平面图转对偶图&rpar;

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

  4. 4541&colon; &lbrack;Hnoi2016&rsqb;矿区

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

  5. BZOJ 4423&colon; &lbrack;AMPPZ2013&rsqb;Bytehattan 平面图转对偶图 &plus; 并查集

    Description 比特哈顿镇有n*n个格点,形成了一个网格图.一开始整张图是完整的.有k次操作,每次会删掉图中的一条边(u,v),你需要回答在删除这条边之后u和v是否仍然连通. Input 第一 ...

  6. bzoj 4756&colon; &lbrack;Usaco2017 Jan&rsqb;Promotion Counting【dfs&plus;树状数组】

    思路还是挺好玩的 首先简单粗暴的想法是dfs然后用离散化权值树状数组维护,但是这样有个问题就是这个全局的权值树状数组里并不一定都是当前点子树里的 第一反应是改树状数组,但是显然不太现实,但是可以这样想 ...

  7. BZOJ 1086:&lbrack;SCOI2005&rsqb;王室联邦(DFS树分块)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1086 题意:给出n个点的树,让你对树进行分块,每块的大小范围在[b, 3b]之间. 思路:一开始想着 ...

  8. bzoj 4540&colon; &lbrack;Hnoi2016&rsqb;序列【单调栈&plus;线段树】

    强烈安利:http://blog.csdn.net/qq_34637390/article/details/51313126 这篇讲标记讲的非常好,这个标记非常神奇-- 首先last表示扫描到last ...

  9. &lbrack;HNOI2016&rsqb;矿区

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

随机推荐

  1. centos7 升级内核到最新版本

    centos7 从问世以来,官网提供的镜像始终是3.10 版本,该版本最大的一个问题是对硬件驱动(尤其是无线网卡)的支持不是很好,本人亲测>5种机型,无线网卡均无法正常使用,如果是非主流机型,手 ...

  2. ABAP 承运路单

    *&---------------------------------------------------------------------* *& Report  ZSDR010 ...

  3. C&num; 深拷贝通用方法

    C#深拷贝通用方法(引用类型的拷贝) /// <summary> /// 深度COPY /// </summary> /// <typeparam name=" ...

  4. Html-Css-div标签设定-剧中

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. HttpClient使用笔记

    使用版本为4.5.1 常用API: 1.获取网页内容:InputStream in = response.getEntity().getContent() 2.获取状态码:response.getSt ...

  6. 【web安全】-- springboot实现两次MD5加密

    一.为什么要做两次MD5 客户端MD5:HTTP在网络上是使用明文传输,用户输入的明文密码直接在网络上传输太危险.所以,在客户端先进行一次MD5(明文+固定盐). 服务端:服务端接受到后,也不是直接写 ...

  7. MVC4中control的增删改查

    public class TestController : Controller { private LeaveEntities db = new LeaveEntities(); // // GET ...

  8. Notepad&plus;&plus;中F3直接搜索选中文字

    用了Notepad++好久了,一直被"F3不能直接搜索选中文字"困扰.毕竟以前习惯UltraEdit的这种操作,很便捷.今天突然发现原来Notepad++快捷键里可以修改这个功能, ...

  9. 开机启动顺序rc&period;local与chkconfig的不同

    /etc/rc.local文件有如下两行/etc/init.d/mysql start/etc/init.d/keepalived start /etc/rc.local是按脚本的顺序一个启动后启动下 ...

  10. Java 中 i&plus;&plus;和&plus;&plus;i的区别

    public class Test{ public static void main(String [] args){ int i = 1; int s = ++i; int x= i++; Syst ...