【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;
}