P8734 奇偶覆盖 题解
Statement
矩形面积并,但是覆盖奇数次、覆盖偶数次的面积要分别输出。
Solution
提供一种不费脑子的做法:
首先离散化、扫描线,问题变成维护区间 +1-1、询问全局有多少正数是奇数、多少正数是偶数。
若去除“正数”的条件,这是很容易用一个标记下传的线段树维护的,区间分别维护 0,1 个数、加法标记,一个区间 +1 或 -1 就 swap(cnt0, cnt1)
。
但是有“正数”的条件,这时偶数的答案需要减去 0 的数量,而“区间 +1-1、询问全局 0 的数量”就用原版扫描线线段树的方法来维护就行了!
所以我们维护两棵线段树,一棵标记下传,一棵不下传,分别维护奇偶数的数量、0 的数量,修改时两棵线段树同步修改即可。
时间 。
代码很可读:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6 + 10; struct Rec { int Lx, Ly, Rx, Ry; } rec[N]; int n; struct Operation { int L, R, x, add; } Ops[N]; int optot; int Ytot, Y[N]; namespace SegA { int len[N << 2], add[N << 2], zero[N << 2]; #define lc (u << 1) #define rc ((u << 1) | 1) #define mid ((l + r) >> 1) void up(int u) { if (add[u]) { zero[u] = 0; } else { zero[u] = zero[lc] + zero[rc]; } } void build(int u, int l, int r) { len[u] = Y[r + 1] - Y[l]; zero[u] = len[u]; add[u] = 0; if (l == r) return; build(lc, l, mid), build(rc, mid + 1, r); } void upd(int u, int l, int r, int x, int y, int v) { if (y < l || r < x) return; if (x <= l && r <= y) { add[u] += v; if (add[u]) { zero[u] = 0; } else { if (l == r) zero[u] = len[u]; else zero[u] = zero[lc] + zero[rc]; } return; } upd(lc, l, mid, x, y, v), upd(rc, mid + 1, r, x, y, v), up(u); } #undef lc #undef rc #undef mid } namespace SegB { int len[N << 2], add[N << 2], odd[N << 2], even[N << 2]; #define lc (u << 1) #define rc ((u << 1) | 1) #define mid ((l + r) >> 1) void up(int u) { odd[u] = odd[lc] + odd[rc]; even[u] = even[lc] + even[rc]; } void Add(int u) { add[u] ^= 1, swap(odd[u], even[u]); } void down(int u) { if (add[u]) Add(lc), Add(rc), add[u] ^= 1; } void build(int u, int l, int r) { len[u] = Y[r + 1] - Y[l], add[u] = 0, odd[u] = 0, even[u] = len[u]; if (l == r) return; build(lc, l, mid), build(rc, mid + 1, r); } void upd(int u, int l, int r, int x, int y) { if (y < l || r < x) return; if (x <= l && r <= y) return Add(u); down(u), upd(lc, l, mid, x, y), upd(rc, mid + 1, r, x, y), up(u); } #undef lc #undef rc #undef mid } int main() { ios::sync_with_stdio(false), cin.tie(nullptr); cin >> n; for (int i = 1; i <= n; ++i) { cin >> rec[i].Lx >> rec[i].Ly >> rec[i].Rx >> rec[i].Ry; Y[++Ytot] = rec[i].Ly, Y[++Ytot] = rec[i].Ry; Ops[++optot] = (Operation){rec[i].Ly, rec[i].Ry, rec[i].Lx, 1}; Ops[++optot] = (Operation){rec[i].Ly, rec[i].Ry, rec[i].Rx, -1}; } sort(Y + 1, Y + Ytot + 1); Ytot = unique(Y + 1, Y + Ytot + 1) - Y - 1; auto GetY = [&](int y) { return lower_bound(Y + 1, Y + Ytot + 1, y) - Y; }; sort(Ops + 1, Ops + optot + 1, [&](Operation u, Operation v) -> bool { return u.x == v.x ? u.add > v.add : u.x < v.x; }); for (int i = 1; i <= optot; ++i) Ops[i].L = GetY(Ops[i].L), Ops[i].R = GetY(Ops[i].R) - 1; --Ytot; SegA::build(1, 1, Ytot); SegB::build(1, 1, Ytot); ll Odd = 0, Even = 0; for (int i = 1; i <= optot; ++i) { SegA::upd(1, 1, Ytot, Ops[i].L, Ops[i].R, Ops[i].add); SegB::upd(1, 1, Ytot, Ops[i].L, Ops[i].R); if (Ops[i].x != Ops[i + 1].x && i != optot) { ll len = Ops[i + 1].x - Ops[i].x; Odd += len * SegB::odd[1]; Even += len * (SegB::even[1] - SegA::zero[1]); } } cout << Odd << '\n' << Even << '\n'; return 0; }
本文作者:Laijinyi
本文链接:https://www.cnblogs.com/laijinyi/p/18363191
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步