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

矿区

题目链接: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;
}