【luogu P3249】【LOJ 2052】矿区(对偶图)(dfs)

矿区

题目链接:luogu P3249 / LOJ 2052

题目大意

一个平面图上被划分成了若干个多边形。
边界一定是正整数,而且一个多边形的贡献是它面积的平方。
然后每次给你围一个多边形,保证有原本划分的若干个多边形组成。
然后每次问你每个在这个多边形每个原本划分的多边形贡献的和,除这个多边形的面积。

思路

发现如果我们把多边形看成点,那我们每次围出来的就是一个连通块。
如果建出生成树,就是生成树上的一个连通块。

那这个可以理解为把面看成点,那不就是转成对偶图就行了。
那你随便选一棵生成树建,然后你考虑怎么快速找这个连通块。

那你考虑枚举那个多边形的边,然后你考虑看:
如果它不在生成树上的边(就是它隔开的两个面在对偶图上的点不连边)
那如果是,那你就判断一下它面向多边形内部的哪一方是父亲还是儿子,那如果是儿子,那就加上儿子子树的大小,如果是父亲就减去儿子子树的大小。
(因为是儿子说明连通块在子树里面,如果是父亲说明连通块在子树外,在上面)
(那这就相当于在最上面的位置加了值,然后再没有儿子的最下面把它儿子都减了)

不过要注意的是对偶图上一条边可能在原图上是若干条边,但你只能统计一次,所以你可以用一个 bool 统计一下是否统计过,然后用一个桶记录你统计过那些,这样就可以正确的时间清空 bool 数组。

然后。
千万!千万不要用 map!
(有人用 map 开写然后卡了一天的常)

代码

没有 map 飞快

#include<map> #include<cmath> #include<cstdio> #include<vector> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N = 2e5 + 5; const int M = N * 6; struct node { int x, y; }a[N]; int n, m, k, tot, rt, P, b[N]; struct FK { int id, y; double jb; }; vector <FK> G[N]; int bh[M], bl[M], idtot, intong[M], dj[M]; ll s[M], ss[M]; bool in[M]; vector <int> pla[N]; int id[M]; //map <pair <int, int>, int> id; inline ll Abs(ll x) {return x < 0 ? -x : x;} inline ll gcd(ll x, ll y) { if (!y) return x; return gcd(y, x % y); } bool operator <(FK x, FK y) { return x.jb < y.jb; } inline node operator -(node x, node y) {return (node){x.x - y.x, x.y - y.y};} inline ll operator *(node x, node y) {return 1ll * x.x * y.y - 1ll * x.y * y.x;} struct DuiOou { struct node { int to, nxt; }e[M]; int le[M], KK, fat[M]; inline void add(int x, int y) { e[++KK] = (node){y, le[x]}; le[x] = KK; } void dfs(int now, int father, int S) { dj[++dj[0]] = now; if (now == S) return ; int to = bh[father ^ 1] + 1; if (to == G[now].size()) to = 0; bl[G[now][to].id] = tot; dfs(G[now][to].y, G[now][to].id, S); } void build() { for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) if (!bl[G[i][j].id]) { tot++; bl[G[i][j].id] = tot; dj[0] = 0; dfs(G[i][j].y, G[i][j].id, i); for (int k = 2; k < dj[0]; k++) { int x = k, y = x + 1; x = dj[x]; y = dj[y]; s[tot] += (a[y] - a[dj[1]]) * (a[x] - a[dj[1]]); } if (s[tot] < 0) rt = tot; } for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) { int x = bl[G[i][j].id], y = bl[G[i][j].id ^ 1]; add(x, y); } } void dfs1(int now, int father) { in[now] = 1; ss[now] = s[now] * s[now]; for (int i = le[now]; i; i = e[i].nxt) if (e[i].to != father && !in[e[i].to]) { dfs1(e[i].to, now); fat[e[i].to] = now; s[now] += s[e[i].to]; ss[now] += ss[e[i].to]; } } void work() { dfs1(rt, 0); for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) { int x = bl[G[i][j].id], y = bl[G[i][j].id ^ 1]; if (fat[x] != y && fat[y] != x) id[G[i][j].id] = 0; else if (fat[y] == x) id[G[i][j].id] = y; else id[G[i][j].id] = -x; } } }T; int re, zf; char c; inline int read() { re = 0; zf = 1; c = getchar(); while (c < '0' || c > '9') { if (c == '-') zf = -1; c = getchar(); } while (c >= '0' && c <= '9') { re = (re << 3) + (re << 1) + c - '0'; c = getchar(); } return re * zf; } inline void write(ll x) { if (x < 10) { putchar('0' ^ x); return ; } write(x / 10); putchar('0' ^ (x % 10)); } int main() { // freopen("mine8.in", "r", stdin); // freopen("write.txt", "w", stdout); idtot = 1; n = read(); m = read(); k = read(); for (int i = 1; i <= n; i++) { a[i] = (node){read(), read()}; } for (int i = 1; i <= m; i++) { int x = read(), y = read();// id[make_pair(x, y)] = ++idtot; id[make_pair(y, x)] = ++idtot; G[x].push_back((FK){++idtot, y, atan2(a[y].y - a[x].y, a[y].x - a[x].x)}); G[y].push_back((FK){++idtot, x, atan2(a[x].y - a[y].y, a[x].x - a[y].x)}); } for (int i = 1; i <= n; i++) { sort(G[i].begin(), G[i].end()); for (int j = 0; j < G[i].size(); j++) bh[G[i][j].id] = j; } T.build(); T.work(); memset(bh, 0, sizeof(bh)); ll ans1, ans2, tmp; int x, y, now, Now; for (int tp = 1; tp <= k; tp++) { b[0] = (read() + P) % n + 1; for (int i = 1; i <= b[0]; i++) b[i] = (read() + P) % n + 1; b[b[0] + 1] = b[1]; ans1 = 0, ans2 = 0; for (int i = 1; i <= b[0]; i++) { x = b[i], y = b[i + 1]; now = id[(*lower_bound(G[x].begin(), G[x].end(), (FK){0, y, atan2(a[y].y - a[x].y, a[y].x - a[x].x)})).id]; if (!now) continue; int Now = Abs(now); if (bh[Now]) continue; bh[Now] = 1; intong[++intong[0]] = Now; if (now > 0) ans1 += s[now], ans2 += ss[now]; else ans1 -= s[-now], ans2 -= ss[-now]; } while (intong[0]) bh[intong[intong[0]]] = 0, intong[0]--; ans1 = ans1 << 1; ans1 = Abs(ans1); ans2 = Abs(ans2); tmp = gcd(ans1, ans2); ans1 /= tmp; ans2 /= tmp; write(ans2); putchar(' '); write(ans1); putchar('\n'); P = ans2 % n; } return 0; }

1 个 map 能过 loj(Ofast)

#include<map> #include<cmath> #include<cstdio> #include<vector> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N = 2e5 + 5; const int M = N * 6; struct node { int x, y; }a[N]; int n, m, k, tot, rt, P, b[N]; struct FK { int id, y; double jb; }; vector <FK> G[N]; int bh[M], bl[M], idtot, intong[M], dj[M]; map <pair <int, int>, int> id; ll s[M], ss[M]; bool in[M]; inline ll Abs(ll x) {return x < 0 ? -x : x;} inline ll gcd(ll x, ll y) { if (!y) return x; return gcd(y, x % y); } inline bool cmp(FK x, FK y) { return x.jb < y.jb; } inline node operator -(node x, node y) {return (node){x.x - y.x, x.y - y.y};} inline ll operator *(node x, node y) {return 1ll * x.x * y.y - 1ll * x.y * y.x;} struct DuiOou { struct node { int to, nxt; }e[M]; int le[M], KK, fat[M]; inline void add(int x, int y) { e[++KK] = (node){y, le[x]}; le[x] = KK; } void dfs(int now, int father, int S) { dj[++dj[0]] = now; if (now == S) return ; int to = bh[father ^ 1] + 1; if (to == G[now].size()) to = 0; bl[G[now][to].id] = tot; dfs(G[now][to].y, G[now][to].id, S); } void build() { for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) if (!bl[G[i][j].id]) { tot++; bl[G[i][j].id] = tot; dj[0] = 0; dfs(G[i][j].y, G[i][j].id, i); for (int k = 2; k < dj[0]; k++) { int x = k, y = x + 1; x = dj[x]; y = dj[y]; s[tot] += (a[y] - a[dj[1]]) * (a[x] - a[dj[1]]); } if (s[tot] < 0) rt = tot; } for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) { int x = bl[G[i][j].id], y = bl[G[i][j].id ^ 1]; add(x, y); } } void dfs1(int now, int father) { in[now] = 1; ss[now] = s[now] * s[now]; for (int i = le[now]; i; i = e[i].nxt) if (e[i].to != father && !in[e[i].to]) { dfs1(e[i].to, now); fat[e[i].to] = now; s[now] += s[e[i].to]; ss[now] += ss[e[i].to]; } } void work() { dfs1(rt, 0); for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) { int x = bl[G[i][j].id], y = bl[G[i][j].id ^ 1]; if (fat[x] != y && fat[y] != x) id[make_pair(i, G[i][j].y)] = 0; else if (fat[y] == x) id[make_pair(i, G[i][j].y)] = y; else id[make_pair(i, G[i][j].y)] = -x; } } }T; int re, zf; char c; inline int read() { re = 0; zf = 1; c = getchar(); while (c < '0' || c > '9') { if (c == '-') zf = -1; c = getchar(); } while (c >= '0' && c <= '9') { re = (re << 3) + (re << 1) + c - '0'; c = getchar(); } return re * zf; } inline void write(ll x) { if (x < 10) { putchar('0' ^ x); return ; } write(x / 10); putchar('0' ^ (x % 10)); } int main() { freopen("mine8.in", "r", stdin); freopen("write.txt", "w", stdout); idtot = 1; n = read(); m = read(); k = read(); for (int i = 1; i <= n; i++) { a[i] = (node){read(), read()}; } for (int i = 1; i <= m; i++) { int x = read(), y = read(); id[make_pair(x, y)] = ++idtot; id[make_pair(y, x)] = ++idtot; G[x].push_back((FK){idtot - 1, y, atan2(a[y].y - a[x].y, a[y].x - a[x].x)}); G[y].push_back((FK){idtot, x, atan2(a[x].y - a[y].y, a[x].x - a[y].x)}); } for (int i = 1; i <= n; i++) { sort(G[i].begin(), G[i].end(), cmp); for (int j = 0; j < G[i].size(); j++) bh[G[i][j].id] = j; } T.build(); T.work(); memset(bh, 0, sizeof(bh)); ll ans1, ans2, tmp; int x, y, now, Now; for (int tp = 1; tp <= k; tp++) { b[0] = (read() + P) % n + 1; for (int i = 1; i <= b[0]; i++) b[i] = (read() + P) % n + 1; b[b[0] + 1] = b[1]; ans1 = 0, ans2 = 0; for (int i = 1; i <= b[0]; i++) { x = b[i], y = b[i + 1]; now = id[make_pair(x, y)]; if (!now) continue; Now = Abs(now); if (bh[Now]) continue; bh[Now] = 1; intong[++intong[0]] = Now; if (now > 0) ans1 += s[now], ans2 += ss[now]; else ans1 -= s[-now], ans2 -= ss[-now]; } while (intong[0]) bh[intong[intong[0]]] = 0, intong[0]--; ans1 = ans1 << 1; ans1 = Abs(ans1); ans2 = Abs(ans2); tmp = gcd(ans1, ans2); ans1 /= tmp; ans2 /= tmp; write(ans2); putchar(' '); write(ans1); putchar('\n'); P = ans2 % n; } return 0; }

2/3 个 map 寄麻了

#include<map> #include<cmath> #include<cstdio> #include<vector> #include<algorithm> #define ll long long using namespace std; const int N = 2e5 + 1; const int M = N * 6; const double eps = 1e-10; struct node { int x, y; }a[N]; int n, m, k, tot, rt, P, b[N]; struct FK { int y; double jb; }; vector <FK> G[N]; map <pair <int, int>, int> bh, bl, ontree; vector <int> dj[M]; ll s[M], ss[M]; bool in[M]; ll Abs(ll x) {return x < 0 ? -x : x;} ll gcd(ll x, ll y) { if (!y) return x; return gcd(y, x % y); } double Abs(double x) {return x < 0 ? -x : x;} bool cmp(FK x, FK y) { return Abs(x.jb - y.jb) < eps ? x.y < y.y : x.jb < y.jb; } node operator +(node x, node y) {return (node){x.x + y.x, x.y + y.y};} node operator -(node x, node y) {return (node){x.x - y.x, x.y - y.y};} ll operator *(node x, node y) {return 1ll * x.x * y.y - 1ll * x.y * y.x;} struct DuiOou { struct node { int to, nxt; }e[M]; int le[M], KK; void add(int x, int y) { e[++KK] = (node){y, le[x]}; le[x] = KK; } void dfs(int now, int father, int S) { dj[tot].push_back(now); bl[make_pair(father, now)] = tot; if (now == S) return ; int to = (bh[make_pair(now, father)] + 1) % G[now].size(); dfs(G[now][to].y, now, S); } void build() { for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) if (!bl.count(make_pair(i, G[i][j].y))) { tot++; dfs(G[i][j].y, i, i); for (int k = 1; k < dj[tot].size() - 1; k++) { int x = k, y = x + 1; x = dj[tot][x]; y = dj[tot][y]; s[tot] += (a[y] - a[dj[tot][0]]) * (a[x] - a[dj[tot][0]]); } if (s[tot] < 0) rt = tot; } for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) { int x = bl[make_pair(i, G[i][j].y)], y = bl[make_pair(G[i][j].y, i)]; // add(bl[make_pair(i, G[i][j])], bl[make_pair(G[i][j], i)]); add(x, y); } } void dfs1(int now, int father) { in[now] = 1; ss[now] = s[now] * s[now]; for (int i = le[now]; i; i = e[i].nxt) if (e[i].to != father && !in[e[i].to]) { dfs1(e[i].to, now); ontree[make_pair(now, e[i].to)] = 1; ontree[make_pair(e[i].to, now)] = 2; s[now] += s[e[i].to]; ss[now] += ss[e[i].to]; } } void work() { dfs1(rt, 0); } }T; int re, zf; char c; int read() { re = 0; zf = 1; c = getchar(); while (c < '0' || c > '9') { if (c == '-') zf = -zf; c = getchar(); } while (c >= '0' && c <= '9') { re = (re << 3) + (re << 1) + c - '0'; c = getchar(); } return re * zf; } int main() { // freopen("mine8.in", "r", stdin); // freopen("write.txt", "w", stdout); n = read(); m = read(); k = read(); for (int i = 1; i <= n; i++) { a[i] = (node){read(), read()}; } for (int i = 1; i <= m; i++) { int x = read(), y = read(); G[x].push_back((FK){y, atan2(a[y].y - a[x].y, a[y].x - a[x].x)}); G[y].push_back((FK){x, atan2(a[x].y - a[y].y, a[x].x - a[y].x)}); } for (int i = 1; i <= n; i++) { sort(G[i].begin(), G[i].end(), cmp); for (int j = 0; j < G[i].size(); j++) bh[make_pair(i, G[i][j].y)] = j; } T.build(); T.work(); bh.clear(); for (int tp = 1; tp <= k; tp++) { b[0] = (read() + P) % n + 1; for (int i = 1; i <= b[0]; i++) b[i] = (read() + P) % n + 1; b[b[0] + 1] = b[1]; // scanf("%d", &b[0]); b[0] = (b[0] + P % n) % n + 1; for (int i = 1; i <= b[0]; i++) scanf("%d", &b[i]), b[i] = (b[i] + P % n) % n + 1; b[b[0] + 1] = b[1]; ll ans1 = 0, ans2 = 0; for (int i = 1; i <= b[0]; i++) { int x = b[i], y = b[i + 1]; int tmpx = bl[make_pair(x, y)], tmpy = bl[make_pair(y, x)]; if (bh[make_pair(tmpx, tmpy)]) continue; bh[make_pair(tmpx, tmpy)] = 1; int op = ontree[make_pair(tmpx, tmpy)]; if (!op) continue; if (op == 1) ans1 += s[tmpy], ans2 += ss[tmpy]; else ans1 -= s[tmpx], ans2 -= ss[tmpx]; } bh.clear(); ans1 = ans1 * 2; ans1 = Abs(ans1); ans2 = Abs(ans2); ll tmp = gcd(ans1, ans2); ans1 /= tmp; ans2 /= tmp; printf("%lld %lld\n", ans2, ans1); P = ans2 % n; } return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P3249.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示