[HNOI2016]礦區
阿新 • • 發佈:2019-03-26
digi end stdin abs 每一個 type emp int amp
題面
給定平面上許多的區域,每次詢問一些點所包圍的子區域的面積平方之和與總面積之和之比,強制在線。
\(\text{Solution}\)
毒瘤至極
顯然我們要維護每一個小區域的面積,由於我們要維護的是一個面,所以我們將平面圖轉對偶圖(不會的戳這裏)。面的信息就縮在一個點中,以無窮域為根隨便弄出個生成樹,對於任意點x處理出以x為根的子樹所代表的區域的面積。
那麽對於一組詢問,我們掃描它的每一條邊,看它的反向邊是否是它的父親,如果是,則加上自己子樹的面積,否則減去子樹的面積。
顯然這麽毒瘤的題我是碼不出的。
不過如果之前學過對偶圖,思維難度並不大。
#include <set> #include <vector> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <assert.h> #include <algorithm> using namespace std; #define LL long long #define debug(...) fprintf(stderr, __VA_ARGS__) #define GO debug("GO\n") inline int rint() { register int x = 0, f = 1; register char c; while (!isdigit(c = getchar())) if (c == '-') f = -1; while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getchar())); return x * f; } template<typename T> inline void chkmin(T &a, T b) { a > b ? a = b : 0; } template<typename T> inline void chkmax(T &a, T b) { a < b ? a = b : 0; } const int N = 2e5 + 10, M = 1.2e6 + 5; const double eps = 1e-10; #define Iter vector<Edge>::iterator LL ans1, ans2; int n, m, Q, tot = 1, cnt, root; struct vec { int x, y; vec(int _x = 0, int _y = 0) {x = _x, y = _y;} vec operator- (const vec &b) const { return vec(x - b.x, y - b.y); } LL operator* (const vec &b) const { return 1ll * x * b.y - 1ll * y * b.x;} } P[N]; struct Edge { int id, u, v; double angle;//atan2 rad bool operator< (const Edge &b) const { return fabs(angle - b.angle) < eps ? v < b.v : angle < b.angle; } } E[M]; int nxt[M], pos[M], fa[M], vis[M], intree[M], ask[M]; LL s[M], ss[M]; vector<Edge> G[N], tree[M]; void add(int u, int v) { E[++tot] = (Edge) {tot, u, v, atan2(P[v].y - P[u].y, P[v].x - P[u].x)}; G[u].push_back(E[tot]); } void Build() { for (int i = 1; i <= n; ++ i) sort(G[i].begin(), G[i].end()); for (int i = 2; i <= tot; ++ i) { int v = E[i].v; Iter it = lower_bound(G[v].begin(), G[v].end(), E[i ^ 1]); if (it == G[v].begin()) it = G[v].end(); --it; nxt[i] = it->id; } for (int i = 2; i <= tot; ++ i) { if (pos[i]) continue; pos[i] = pos[nxt[i]] = ++cnt; for (int j = nxt[i]; E[j].v != E[i].u; j = nxt[j], pos[j] = cnt) s[cnt] += (P[E[j].u] - P[E[i].u]) * (P[E[j].v] - P[E[i].u]); if (s[cnt] <= 0) root = cnt; } for (int i = 2; i <= tot; ++ i) tree[pos[i]].push_back((Edge){i, pos[i], pos[i ^ 1]}); } void DFS(int u, int las) { fa[u] = las; ss[u] = s[u] * s[u]; s[u] <<= 1; vis[u] = 1; for (int i = 0; i < tree[u].size(); ++ i) { int v = tree[u][i].v; if (vis[v]) continue; intree[tree[u][i].id] = intree[tree[u][i].id ^ 1] = 1; DFS(v, u); s[u] += s[v]; ss[u] += ss[v]; } } void solve() { while (Q --) { int tmp = rint(); tmp = (tmp + ans1) % n + 1; for (int i = 1; i <= tmp; ++ i) ask[i] = (rint() + ans1) % n + 1; ask[tmp + 1] = ask[1]; ans1 = ans2 = 0; for (int i = 1; i <= tmp; ++ i) { int x = ask[i], y = ask[i + 1]; Edge xhc = (Edge) {0, x, y, atan2(P[y].y - P[x].y, P[y].x - P[x].x)}; Iter it = lower_bound(G[x].begin(), G[x].end(), xhc); int id = it->id; if (!intree[id]) continue; if (fa[pos[id]] == pos[id ^ 1]) ans1 += ss[pos[id]], ans2 += s[pos[id]]; else ans1 -= ss[pos[id ^ 1]], ans2 -= s[pos[id ^ 1]]; } LL gcd = __gcd(ans1, ans2); ans1/=gcd, ans2/=gcd; printf("%lld %lld\n", ans1, ans2); } } int main() { #ifndef ONLINE_JUDGE freopen("xhc.in", "r", stdin); freopen("xhc.out", "w", stdout); #endif n = rint(), m = rint(), Q = rint(); for (int i = 1; i <= n; ++ i) { int u = rint(), v = rint(); P[i] = vec(u, v); } for (int i = 1; i <= m; ++ i) { int x = rint(), y = rint(); add(x, y), add(y, x); } Build(); DFS(root, 0); solve(); }
[HNOI2016]礦區