題意:求重疊矩形的周長。
題解:枚舉x區間時要注意求出, y 軸投影的線段數量。 即對應一個 x 有多少段不連續的線段,因為這關係的矩形的寬。 對 x 進行排列要記得入邊在前,出邊在後,否則邊相交的兩個矩形,就會把重邊也計算在內。
#include <cmath>#include <algorithm>#include <iostream>using namespace std;#define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define N 20010int y[N*2];struct Node { int l, r, len, lc, rc, cover, cnt; /* lc, rc, 表示定的被覆蓋的次數 */} node[N*4];struct Line{ int x, y1, y2, flag;} line[N*2];bool cmp ( Line a, Line b ){ if ( a.x != b.x ) return a.x < b.x; return a.flag > b.flag; /* 當 x 相同時應當是入邊在前, 畫兩個矩形分析分析 */}void y_update ( int u ){ if ( node[u].cover > 0 ) node[u].len = y[node[u].r] - y[node[u].l]; else if ( node[u].l + 1 == node[u].r ) node[u].len = 0; else node[u].len = node[L(u)].len + node[R(u)].len; if ( node[u].cover > 0 ) node[u].cnt = 1; /* cnt 記錄投影到 y 軸上的線段數( 即不連續的段數) */ else { node[u].cnt = node[L(u)].cnt + node[R(u)].cnt; if ( node[R(u)].lc != 0 && node[L(u)].rc != 0 ) /*左子樹的右端點如果跟右子樹的左端點都被覆蓋了,說明在整個區間裡,有一個區間橫跨左右子樹,但被重複計算了,所以要減去1 */ node[u].cnt--; }}void build( int u, int l, int r ){ node[u].l = l; node[u].r = r; node[u].cnt = 0; node[u].len = node[u].cover = 0; node[u].lc = node[u].rc = 0; if ( l + 1 == r ) return; int mid = ( l + r ) >> 1; build ( L(u), l, mid ); build ( R(u), mid, r );}void update ( int u, Line e ){ if ( e.y1 == y[node[u].l] ) node[u].lc += e.flag; if ( e.y2 == y[node[u].r] ) node[u].rc += e.flag; if ( e.y1 == y[node[u].l] && e.y2 == y[node[u].r] ) { node[u].cover += e.flag; y_update ( u ); return; } if ( e.y1 >= y[node[R(u)].l] ) update ( R(u), e ); else if ( e.y2 <= y[node[L(u)].r] ) update ( L(u), e ); else { Line temp1 = e; Line temp2 = e; temp1.y2 = y[node[L(u)].r]; temp2.y1 = y[node[R(u)].l]; update ( L(u), temp1 ); update ( R(u), temp2 ); } y_update ( u );}int main(){ //freopen ( "a.txt", "r", stdin ); int n, i, k, x1, y1, x2, y2; while ( scanf("%d",&n) != EOF ) { for ( i = k = 1; i <= n; i++, k++ ) { scanf("%d %d %d %d", &x1, &y1, &x2, &y2 ); line[k].x = x1; line[k].y1 = y1; line[k].y2 = y2; line[k].flag = 1; y[k] = y1; k++; line[k].x = x2; line[k].y1 = y1; line[k].y2 = y2; line[k].flag = -1; y[k] = y2; } sort ( line+1, line+k, cmp ); sort ( y+1, y+k ); build ( 1, 1, k-1 ); update ( 1, line[1] ); int ans = node[1].len; int temp = node[1].len; int tcnt = node[1].cnt; for ( i = 2; i < k; i++ ) { update ( 1, line[i] ); ans += abs ( node[1].len - temp ); ans += 2 * ( line[i].x - line[i-1].x ) * tcnt; temp = node[1].len; tcnt = node[1].cnt; } printf ( "%d\n", ans ); } return 0;}