给出n 个矩形,求它们的面积并。 更准确一点,每个矩形将给出它的左上角和右下角的位置:x1; y1; x2; y2 这四个数都是整数且满足x1 x2; y1 y2. Input 第1 行1 个整数:n,表示矩形的个数。 接下来n 行,每行4 个整数:x1 y1 x2 y2,表示一个矩形的左上角和右下角的坐标。 Output 输出area。 Sample area.in 3 1 1 2 3 1 2 3 3 3 3 4 4 area.out 11 样例解释:一共有11 个点落在了上面三个矩形所表示的区域内: (1; 1); (1; 2); (1; 3); (2; 1); (2; 2); (2; 3); (3; 2); (3; 3); (3; 4); (4; 3); (4; 4)
扫描线,对于一个举行(x1,y1,x2,y2),将它看成两个事件:在x1 这个时间将 (y1,y2) 这个区间加一,在x2+1 这个时间将(y1,y2) 这个区间减一。 这样,我们遍历整个时间,并在执行完这个时间的操作后看看有多少位置非0, 将其数量加到答案中,就完了,当然时间不能傻傻地一个一个枚,因为关键的时间点最多2n 个,其它时候面积是没有变的,所以要一段一段地算。至于怎么用线段树实现那么查看有多少个非零的位置,需要注意对于任何一个减一操作,前面一定有一个和它一样的加一操作,就只需要维护一下每个节点被完全覆盖的次数。再用另一个来统计子树中的那些修改导致这个节点还有 多少个非零。有点像标记永久化
#include "cctype" #include "cstdio" #include "algorithm" const int MAXN = (int) 1e5 + 5; const int Ins = 1, Del = -1; typedef long long LL; template <class T> inline bool readIn(T &x) { T opt = 1; char ch; while( !isdigit(ch = (char) getchar()) && (ch ^ -1) && (ch ^ 45) ); if(ch == -1) return false; if(ch == 45) opt = -1, ungetc(ch, stdin); for(x = ch - 48; isdigit(ch = (char) getchar()); x = (x << 1) + (x << 3) + ch - 48); x *= opt; } struct Events { int type, time, lf, rg; Events(int type = 0, int time = 0, int lf = 0, int rg = 0) : type(type), time(time), lf(lf), rg(rg) { } inline bool operator < (const Events &rhs) const { return time < rhs.time; } } events[MAXN << 1]; struct node { int cnt, sum; node *ls, *rs; node(int cnt = 0, int sum = 0, node *ls = 0, node *rs = 0) : cnt(cnt), sum(sum), ls(ls), rs(rs) { } inline int query(int lf, int rg) { return cnt ? rg - lf + 1 : sum; } inline void update(int lf, int rg) { int mid = (lf + rg) >> 1; sum = ls -> query(lf, mid) + rs -> query(mid + 1, rg); } } pool[MAXN << 1], *root, *tail = pool; int n, x1, y1, x2, y2, tot; LL ans; node *build(int lf, int rg) { node *nd = ++tail; if( lf == rg ) return nd; int mid = (lf + rg) >> 1; nd -> ls = build(lf, mid); nd -> rs = build(mid + 1, rg); // alredy initialized; return nd; } void modify(node* &nd, int lf, int rg, int L, int R, int delta) { if(L > lf || R < rg) { int mid = (lf + rg) >> 1; if(L <= mid) modify(nd -> ls, lf, mid, L, R, delta); if(R > mid) modify(nd -> rs, mid + 1, rg, L, R, delta); nd -> update(lf, rg); } else nd -> cnt += delta; return; } int main() { freopen("area.in", "r", stdin); freopen("area.out", "w", stdout); readIn(n); for(register int i = 1; i <= n; ++i) { readIn(x1), readIn(y1), readIn(x2), readIn(y2); events[tot++] = Events(1, x1, y1, y2); events[tot++] = Events(-1, x2 + 1, y1, y2); } std::sort(events, events + tot); root = build(1, MAXN); for(register int i = 0, j; i < tot; i = j + 1) { for(j = i; j < tot && events[j + 1].time == events[i].time; ++j); for(register int k = i; k <= j; ++k) modify(root, 1, MAXN, events[k].lf, events[k].rg, events[k].type); if(j ^ (tot - 1)) ans += (LL) root -> query(1, MAXN) * (events[j + 1].time - events[i].time); } printf("%lld\n", ans); return 0; }