【LG3249】[HNOI2016]矿区

题面

洛谷

题解

先平面图转对偶图,

建好了对偶图之后随意拿出一个生成树,以无边界的范围为根。

无边界的范围很好求,用叉积算出有向面积时,算出来是负数的就是无边界的范围。

然后标记所有的树边,记录生成树中每个子树的矿区面积和及面积平方和。

对于每一个询问,先找到询问里出现的边,如果有非树边就忽略,否则如果这条边所在的面是儿子,就加上子树的面积,如果是父亲就减去儿子子树的面积。

这个可以通过画图手玩进行证明。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
const int MAX_N = 2e5 + 5, MAX_M = 1.2e6 + 5;
const double EPS = 1e-10;
struct Point { int x, y; } p[MAX_N];
Point operator - (const Point &l, const Point &r) { return (Point){l.x - r.x, l.y - r.y}; }
long long cross(const Point &l, const Point &r) { return 1ll * l.x * r.y - 1ll * l.y * r.x; }
struct Edge { int id, x, y; double a; } e[MAX_M]; int e_cnt = 0;
bool operator < (const Edge &l, const Edge &r)
{ return fabs(l.a - r.a) < EPS ? l.y < r.y : l.a < r.a; }
vector<Edge> G[MAX_N], T[MAX_M];
void Add_Edge(int u, int v) {
e[e_cnt] = (Edge){e_cnt, u, v, atan2(p[v].y - p[u].y, p[v].x - p[u].x)};
G[u].push_back(e[e_cnt]); e_cnt++;
}
int N, M, Q;
int cnt, root, nxt[MAX_M], pos[MAX_M], fa[MAX_M];
long long ans1, ans2, s1[MAX_M], s2[MAX_M];
void build() {
for (int i = 1; i <= N; i++) sort(G[i].begin(), G[i].end());
for (int i = 0; i < e_cnt; i++) {
int y = e[i].y;
vector<Edge> :: iterator ite = lower_bound(G[y].begin(), G[y].end(), e[i ^ 1]);
if (ite == G[y].begin()) ite = G[y].end();
--ite, nxt[i] = ite -> id;
}
for (int i = 0; i < e_cnt; i++) {
if (pos[i]) continue;
pos[i] = pos[nxt[i]] = ++cnt;
for (int j = nxt[i]; e[j].y != e[i].x; j = nxt[j], pos[j] = cnt)
s1[cnt] += cross(p[e[j].x] - p[e[i].x], p[e[j].y] - p[e[i].x]);
if (s1[cnt] <= 0) root = cnt;
}
for (int i = 0; i < e_cnt; i++)
T[pos[i]].push_back((Edge){i, pos[i], pos[i ^ 1]});
}
bool vis[MAX_M], ist[MAX_M];
void dfs(int x) {
s2[x] = 1ll * s1[x] * s1[x], s1[x] <<= 1ll, vis[x] = 1;
for (int i = 0, sz = T[x].size(); i < sz; i++) {
int y = T[x][i].y; if (vis[y]) continue;
ist[T[x][i].id] = ist[T[x][i].id ^ 1] = 1;
fa[y] = x; dfs(y); s1[x] += s1[y], s2[x] += s2[y];
}
}
long long gcd(long long x, long long y) {
if (y == 0) return x;
else return gcd(y, x % y);
}
int q[MAX_M];
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
N = gi(), M = gi(), Q = gi();
for (int i = 1; i <= N; i++) p[i] = (Point){gi(), gi()};
for (int i = 1; i <= M; i++) {
int u = gi(), v = gi();
Add_Edge(u, v), Add_Edge(v, u);
}
build(); dfs(root);
while (Q--) {
int n = (gi() + ans1) % N + 1;
for (int i = 1; i <= n; i++) q[i] = (gi() + ans1) % N + 1;
q[n + 1] = q[1], ans1 = ans2 = 0;
for (int i = 1; i <= n; i++) {
int x = q[i], y = q[i + 1];
Edge e = (Edge){0, x, y, atan2(p[y].y - p[x].y, p[y].x - p[x].x)};
vector<Edge> :: iterator ite = lower_bound(G[x].begin(), G[x].end(), e);
int j = ite -> id; if (!ist[j]) continue;
if (fa[pos[j]] == pos[j ^ 1]) ans1 += s2[pos[j]], ans2 += s1[pos[j]];
else ans1 -= s2[pos[j ^ 1]], ans2 -= s1[pos[j ^ 1]];
}
long long tmp = gcd(ans1, ans2);
ans1 /= tmp, ans2 /= tmp;
printf("%lld %lld\n", ans1, ans2);
}
return 0;
}

【LG3249】[HNOI2016]矿区的更多相关文章

  1. [HNOI2016]矿区

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

  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. 4541: [Hnoi2016]矿区

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

  5. ●BZOJ 4541 [Hnoi2016]矿区

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

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

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

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

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

  8. 【bzoj4541】 Hnoi2016—矿区

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

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

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

随机推荐

  1. Python学习---Django的request.post源码分析

    request.post源码分析: 可以看到传递json后会帮我们dumps处理一次最后一字节形式传递过去

  2. Linux 系统开机自启的配置文件

    程序开机启动的配置文件(/etc/rc.local) # 系统级别 ntsysv # 图形界面设置自启程序 chkconfig(/etc/init.d/sshd) 处理开机启动的文件 # 用户级别 # ...

  3. September 14th 2017 Week 37th Thursday

    Don't let the past steal your present. 别让过去悄悄偷走了我们的当下. We take what we can get and make the best of ...

  4. September 11th 2017 Week 37th Monday

    I believe there is a hero in all of us. 我相信每个人心中都住着一个英雄. For every of us, there are two version with ...

  5. lambda 形参:返回值 lambda 匿名函数 格式:

    lambda 匿名函数 格式: lambda 形参:返回值 e.g f = lambda n:n**2 print(f(10))

  6. CentOS 7.4 yum安装LAMP环境

    配置防火墙,开启80.3306端口.CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙. #停止firewall服务 systemctl stop firewa ...

  7. 【转】Android应用如何跳转到应用市场详情页面

    Android应用开发过程中,可能会有需求,比如:推广时跳转到应用市场下载应用,跳转到应用市场给自己的应用打分,跳转到应用市场更新自己的应用.那如何跳转到应用市场呢? 可能跳转的方法大家都是知道的,方 ...

  8. Odoo作为后端时如何返回数据给webapp、移动端app

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9307315.html  使用jinja2渲染的页面,可以直接在调用template.render()时传递参数 ...

  9. Apache HttpComponents中的cookie匹配策略

    Apache HttpComponents中的cookie匹配策略 */--> pre.src {background-color: #292b2e; color: #b2b2b2;} pre. ...

  10. Linux终端里的记录器

    我们在调试程序的时候,免不了要去抓一些 log ,然后进行分析. 如果 log 量不是很大的话,那很简单,只需简单的复制粘贴就好. 但是如果做一些压力测试,产生大量 log ,而且系统内存又比较小(比 ...