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

  考虑怎么用对偶图解决原问题。将外围的无限域也作为对偶图中的一个点,以其为根随便找一棵生成树,计算子树内面积和及面积平方和。对于询问,考虑多边形上每条边,其同时也是对偶图中两点的边。如果该边在生成树中是非树边,扔掉不管;如果是树边,若由父亲指向儿子,则加上儿子权值,否则减掉儿子权值。具体只能感性理解。

  注意对偶图中两点间可能有重边,判断是否为非树边时小心一点。因为这个调一年也是没谁了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<cassert>
using namespace std;
#define ll long long
#define Vector point
#define N 400010
#define M 1200010
ll gcd(ll n,ll m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,q,b[N],sur[M],nxt[M],t=-;
map<int,int> id[N],tag;
ll lastx,lasty;
struct point
{
int x,y;
Vector operator +(const Vector&a) const
{
return (Vector){x+a.x,y+a.y};
}
Vector operator -(const Vector&a) const
{
return (Vector){x-a.x,y-a.y};
}
ll operator *(const Vector&a) const
{
return 1ll*x*a.y-1ll*y*a.x;
}
bool operator <(const Vector&a) const
{
return atan2(x,y)<atan2(a.x,a.y);
}
}a[N];
struct edge{int x,y;}e[M];
struct data
{
Vector p;int id;
bool operator <(const data&a) const
{
return p<a.p;
}
};
vector<data> c[N];
namespace newgraph
{
int n,p[N],fa[N],t=,root;
ll sum[N],sqr[N],area[N];
struct data{int to,nxt,id;}edge[M];
void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].id=z,p[x]=t;}
void dfs(int k)
{
sum[k]=area[k]<<,sqr[k]=area[k]*area[k];
for (int i=p[k];i;i=edge[i].nxt)
if (!fa[edge[i].to]&&edge[i].to!=root)
{
tag[edge[i].id]=-,tag[edge[i].id^]=;
fa[edge[i].to]=k;
dfs(edge[i].to);
sum[k]+=sum[edge[i].to],sqr[k]+=sqr[edge[i].to];
}
}
}
void addedge(int x,int y)
{
t++,e[t].x=x,e[t].y=y;id[x][y]=t;
c[x].push_back((data){a[y]-a[x],t});
}
void build()
{
for (int i=;i<=n;i++)
if (c[i].size())
{
sort(c[i].begin(),c[i].end());
for (int j=;j<c[i].size()-;j++)
nxt[c[i][j].id]=c[i][j+].id;
nxt[c[i][c[i].size()-].id]=c[i][].id;
}
for (int i=;i<(m<<);i++)
if (!sur[i])
{
++newgraph::n;
int x=i;ll y=;
do
{
sur[x]=newgraph::n;
y+=a[e[x].x]*a[e[x].y];
x=nxt[x^];
}while (!sur[x]);
if (y<) newgraph::root=newgraph::n;
newgraph::area[newgraph::n]=y;
}
for (int i=;i<(m<<);i++)
newgraph::addedge(sur[i],sur[i^],i);
newgraph::dfs(newgraph::root);
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4541.in","r",stdin);
freopen("bzoj4541.out","w",stdout);
const char LL[]="%I64d ";
#else
const char LL[]="%lld ";
#endif
n=read(),m=read(),q=read();
for (int i=;i<=n;i++) a[i].x=read(),a[i].y=read();
for (int i=;i<=m;i++)
{
int x=read(),y=read();
addedge(x,y),addedge(y,x);
}
build();
while (q--)
{
int t=(read()+lastx)%n+;
for (int i=;i<=t;i++) b[i]=(read()+lastx)%n+;
lastx=,lasty=;
for (int i=;i<=t;i++)
{
int x=tag[id[b[i]][b[i%t+]]];
if (x)
{
int y=x==?sur[id[b[i]][b[i%t+]]]:sur[id[b[i%t+]][b[i]]];
lasty+=x*newgraph::sum[y],lastx+=x*newgraph::sqr[y];
}
}
ll tmp=gcd(lastx,lasty);
lastx/=tmp,lasty/=tmp;
printf(LL,lastx),printf(LL,lasty),printf("\n");
}
return ;
}

BZOJ4541 HNOI2016矿区(平面图转对偶图)的更多相关文章

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

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

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

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

  3. BZOJ4541 [Hnoi2016]矿区

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  4. [HNOI2016]矿区

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

  5. LOJ#2052. 「HNOI2016」矿区(平面图转对偶图)

    题面 传送门 题解 总算会平面图转对偶图了-- 首先我们把无向边拆成两条单向边,这样的话每条边都属于一个面.然后把以每一个点为起点的边按极角排序,那么对于一条边\((u,v)\),我们在所有以\(v\ ...

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

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

  7. 【LG3249】[HNOI2016]矿区

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

  8. 【BZOJ-2007】海拔 最小割 (平面图转对偶图 + 最短路)

    2007: [Noi2010]海拔 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2095  Solved: 1002[Submit][Status] ...

  9. 平面图转对偶图(Bzoj1001:狼抓兔子)

    如果只会用最小割做这道题那就太菜辣 引入 来自某学长 平面图:在平面上边不相交的图(边可以绕着画) 那么平面图的边与边就围成了许多个区域(这与你画图的方式有关) 定义对偶图:把相邻的两个区域连上边,形 ...

随机推荐

  1. Luogu P4779 【模板】单源最短路径(标准版)(Dijkstra+堆优化模板)

    qwq dij其实和prim挺像的,prim是找权值最小点,dij是找边, 用一个优先队列就可以在加入边的时候直接排序,避免了每次遍历更新min priority_queue <pair< ...

  2. Spark运行时错误与解决

    Spark  java.io.IOException: Filesystem closed partition数量太小,读取数据后进行repartition重新分片再处理. Spark Streami ...

  3. 2-(基础入门篇)Air202下载开发入门(给Air202下载第一个程序)

    http://www.cnblogs.com/yangfengwu/p/8887933.html 资料链接 链接:https://pan.baidu.com/s/1-SRfsKGQ7rZVvFmp1O ...

  4. IIC双向电平转换电路设计

    现代的集成电路工艺加工的间隙可达0.5μm 而且很少限制数字I/O 信号的最大电源电压和逻辑电平. 为了将这些低电压电路与已有的5V或其他I/O电压器件连接起来,接口需要一个电平转换器.对于双向的总线 ...

  5. 【转】分布式一致性算法:Raft 算法(Raft 论文翻译)

    编者按:这篇文章来自简书的一个位博主Jeffbond,读了好几遍,翻译的质量比较高,原文链接:分布式一致性算法:Raft 算法(Raft 论文翻译),版权一切归原译者. 同时,第6部分的集群成员变更读 ...

  6. FreeRTOS 任务与调度器(2)

    在上一篇我们介绍了FreeRTOS任务的一些基本操作和功能,今天我们会介绍一个很好很强大的功能——任务通知 任务通知可以在不同任务之间传递信息,它可以取代二值信号量.计数信号量.事件标志组.深度为1的 ...

  7. Spring 中配置log4j日志功能

    一,添加log4j依赖包 可从官网上下载该依赖包log4j-x.x.xx.jar,下载后 build path,添加依赖包 二,创建 log4j.properties 配置文件 log4j.prope ...

  8. Dethe is my Finaunce金融

    英国诗人乔叟Dethe is my Finaunce金融 英语中“金融”在14世纪,金融计算时间价值的手段.就随机结果签约的能力.一个允许转让金融权后的清算.<Lamentation of Ma ...

  9. python-小知识点-14

    ''' python2 python3 ''' #python2 print() print 'abc' range() xrange() 生成器 raw_input() #python3 print ...

  10. B. Forgery

    链接 [http://codeforces.com/contest/1059/problem/B] 题意 要伪造医生签名,先给你医生的签名nm的网格'.'表示空白',#'表示墨水,你的笔可以这么画以一 ...