我们可以讲块坐标改成点坐标,然后再进行离散化,然后就是一个经典的扫面线问题了,如果b大于1的时候,横着扫完再竖着扫一遍就可以了。
这时候扫描线的pushup该怎么写呢?我们用ls记录当前线段树上的节点的左连续白色的长度,rs记录当前线段树上的节点的右连续白色的长度,tree记录当前线段树上的节点对应的长b宽1的长方形的个数。
于是,pushup就变成了如下情况:
tree[rt] = tree[lsn] + tree[rsn];
(1)如果rs[lsn] >= b && ls[rsn] >= b,此时tree[rt] += b - 1;因为两边的中间合并,并且两边都各自算过贡献了,(b-1)被多算了一遍,所以要加回去;
(2)如果只有rs[lsn] >= b,此时再加上个ls[rsn]即可;
(3)同理ls[rsn] >= b;
(4)剩下的,如果rs[lsn] + ls[rsn] >= b,tree[rt] += rs[lsn] + ls[rsn] - b + 1。
于是,剩下就是简单的扫描线问题了。
当然, 一定不要写错lsn和rsn,不然debug还是蛮累的。
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #include <bitset> #include <unordered_map> #include <unordered_set> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 #define INF 0x3f3f3f3f #define HalF (l + r)>>1 #define lsn rt<<1 #define rsn rt<<1|1 #define Lson lsn, l, mid #define Rson rsn, mid+1, r #define QL Lson, ql, qr #define QR Rson, ql, qr #define myself rt, l, r #define pii pair<int, int> #define MP(a, b) make_pair(a, b) using namespace std; typedef unsigned long long ull; typedef unsigned int uit; typedef long long ll; const int maxN = 2e5 + 7; int C, V, N, a, b, lsan[maxN], _UP; struct Matrice { int lx, ly, rx, ry; void In() { scanf("%d%d%d%d", &lx, &ly, &rx, &ry); rx ++; ry ++; } } t[maxN]; struct Line { int l, r, y, op; Line(int a=0, int b=0, int c=0, int d=0):l(a), r(b), y(c), op(d) {} friend bool operator < (Line e1, Line e2) { return e1.y == e2.y ? e1.op > e2.op : e1.y < e2.y; } } edge[maxN]; const int maxP = maxN << 2; int ls[maxP], rs[maxP], tree[maxP]; ll ans = 0; void build(int rt, int l, int r) { ls[rt] = rs[rt] = lsan[r + 1] - lsan[l]; if(ls[rt] >= b) tree[rt] = ls[rt] - b + 1; if(l == r) return; int mid = HalF; build(Lson); build(Rson); } void pushup(int rt, int l, int r) { int mid = HalF; ls[rt] = ls[lsn]; rs[rt] = rs[rsn]; if(ls[lsn] == lsan[mid + 1] - lsan[l]) ls[rt] += ls[rsn]; if(rs[rsn] == lsan[r + 1] - lsan[mid + 1]) rs[rt] += rs[lsn]; tree[rt] = tree[lsn] + tree[rsn]; if(ls[rsn] + rs[lsn] >= b) { if(ls[rsn] >= b && rs[lsn] >= b) tree[rt] += b - 1; else if(ls[rsn] >= b) tree[rt] += rs[lsn]; else if(rs[lsn] >= b) tree[rt] += ls[rsn]; else tree[rt] += ls[rsn] + rs[lsn] - b + 1; } } void update(int rt, int l, int r, int ql, int qr, int val) { if(ql <= l && qr >= r) { if(val > 0) { ls[rt] = rs[rt] = lsan[r + 1] - lsan[l]; if(ls[rt] >= b) tree[rt] = ls[rt] - b + 1; } else { ls[rt] = rs[rt] = 0; tree[rt] = 0; } return; } int mid = HalF; if(qr <= mid) update(QL, val); else if(ql > mid) update(QR, val); else { update(QL, val); update(QR, val); } pushup(myself); } void Solve() { _UP = 0; int n = 0; for(int i = 1; i <= N; i ++) { lsan[++ _UP] = t[i].ly; lsan[++ _UP] = t[i].ry; edge[++ n] = Line(t[i].ly, t[i].ry, t[i].lx, -1); edge[++ n] = Line(t[i].ly, t[i].ry, t[i].rx, +1); } lsan[++ _UP] = 1; lsan[++ _UP] = V; sort(lsan + 1, lsan + _UP + 1); _UP = (int)(unique(lsan + 1, lsan + _UP + 1) - lsan - 1); sort(edge + 1, edge + n + 1); build(1, 1, _UP - 1); if(n) ans += 1LL * (edge[1].y - 1) * tree[1]; else ans += 1LL * (C - 1) * tree[1]; for(int i = 1, ql, qr; i <= n; i ++) { ql = (int)(lower_bound(lsan + 1, lsan + _UP + 1, edge[i].l) - lsan); qr = (int)(lower_bound(lsan + 1, lsan + _UP + 1, edge[i].r) - lsan - 1); update(1, 1, _UP - 1, ql, qr, edge[i].op); if(i < n) ans += 1LL * (edge[i + 1].y - edge[i].y) * tree[1]; else ans += 1LL * (C - edge[i].y) * tree[1]; } } int main() { scanf("%d%d%d%d%d", &C, &V, &N, &a, &b); C ++; V ++; for(int i = 1; i <= N; i ++) t[i].In(); _UP = 0; int n = 0; for(int i = 1; i <= N; i ++) { lsan[++ _UP] = t[i].lx; lsan[++ _UP] = t[i].rx; edge[++ n] = Line(t[i].lx, t[i].rx, t[i].ly, -1); edge[++ n] = Line(t[i].lx, t[i].rx, t[i].ry, +1); } lsan[++ _UP] = 1; lsan[++ _UP] = C; sort(lsan + 1, lsan + _UP + 1); _UP = (int)(unique(lsan + 1, lsan + _UP + 1) - lsan - 1); sort(edge + 1, edge + n + 1); build(1, 1, _UP - 1); if(n) ans += 1LL * (edge[1].y - 1) * tree[1]; else ans += 1LL * (V - 1) * tree[1]; for(int i = 1, ql, qr; i <= n; i ++) { ql = (int)(lower_bound(lsan + 1, lsan + _UP + 1, edge[i].l) - lsan); qr = (int)(lower_bound(lsan + 1, lsan + _UP + 1, edge[i].r) - lsan - 1); update(1, 1, _UP - 1, ql, qr, edge[i].op); if(i < n) ans += 1LL * (edge[i + 1].y - edge[i].y) * tree[1]; else ans += 1LL * (V - edge[i].y) * tree[1]; } if(b > 1) { Solve(); } printf("%lld\n", ans); return 0; } /* 4 4 2 1 2 1 1 2 2 3 3 4 4 ans:8 */