http://acm.hdu.edu.cn/showproblem.php?pid=1542
题意:
求N个矩形的面积并。
思路:
线段树+扫描线+离散化。首先我们可以将所有的矩形开成有四条边,然后在水平和竖直方向上将区域切割 ,形成所谓的“超元线段”,然后就可以用线段树进行求解了。
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #include<stdlib.h> #include<math.h> using namespace std; #define LL(a) ( (a)<<1 ) #define RR(a) ( (a)<<1|1 ) #define eps (1e-6) const int MAXN = 110<<1 ; int N , NN; struct Seg{ double l, r , h ; int s ; Seg(){} Seg(double a, double b, double c , double ss) :l(a), r(b) , h(c) ,s(ss){} bool operator< ( const Seg& seg) const { return h > seg.h ; } }line[MAXN] ; int col[MAXN<<2] ; int set[MAXN<<2] ; double sum[MAXN<<2] ; double X[MAXN<<2] ; double len[MAXN<<2] ; double s_len[MAXN<<2] ; void build(int l ,int r ,int idx){ col[idx] = 0 ; set[idx] = 0 ; sum[idx] = 0; if(l == r) return ; int mid = (l + r) >> 1 ; build(l , mid , LL(idx)); build(mid+1,r , RR(idx)); } int find(double d,int l , int r ){ int mid ; while(l < r){ mid = (l + r) >> 1 ; if( X[mid] < d ) l = mid + 1 ; else r = mid ; } return l + 1 ; } void down(int l ,int r, int idx){ int mid = (l + r) >> 1 ; if( set[idx] ){ col[ LL(idx) ] = col[idx] ; set[ LL(idx) ] = 1 ; if( col[ LL(idx) ] == 0 ) sum[ LL(idx) ] = 0 ; else sum[ LL(idx) ] = s_len[mid] - s_len[l-1] ; col[ RR(idx) ] = col[idx] ; set[ RR(idx) ] = 1 ; if( col[ RR(idx) ] == 0 ) sum[ RR(idx) ] = 0 ; else sum[ RR(idx) ] = s_len[r] - s_len[mid] ; set[idx] = 0 ; } } void up(int l , int r, int idx ){ if( col[ LL(idx) ] == col[ RR(idx) ] ) col[idx] = col[ LL(idx) ] ; else col[idx] = -1 ; sum[idx] = sum[ LL(idx) ] + sum[ RR(idx) ] ; } void update(int l ,int r, int idx, int a , int b , int v){ if(l==a && r==b && col[idx] != -1 ){ col[idx] += v ; set[idx] = 1 ; if( col[idx] == 0 ) sum[idx] = 0 ; else sum[idx] = s_len[r] - s_len[l-1] ; return ; } down(l, r, idx ); int mid = (l + r) >> 1 ; if( b<=mid ) update(l , mid , LL(idx) , a , b , v ); else if( mid<a ) update(mid+1 , r, RR(idx) , a, b, v ); else{ update(l, mid , LL(idx) ,a ,mid , v); update(mid+1 , r , RR(idx) , mid+1, b , v ); } up(l, r, idx) ; } int main(){ double a, b, c , d ; int cas = 0; while( scanf("%d",&N) && N ){ NN = N<<1 ; for(int i=0;i<N;i++){ scanf("%lf%lf%lf%lf",&a,&b,&c,&d); X[i<<1] = a ; X[i<<1|1] = c ; line[i<<1] = Seg(a , c , b , -1 ); line[i<<1|1] = Seg(a , c ,d ,1 ); } sort(X , X+NN); sort(line , line+NN) ; int k = 0 ; X[k++] = X[0] ; for(int i=1;i<NN;i++){ if( fabs( X[i] - X[i-1] ) <= eps ) continue ; X[k++] = X[i] ; } s_len[0] = 0; for(int i=0;i<k;i++){ len[i+1] = X[i+1] - X[i] ; s_len[i+1] = s_len[i] + len[i+1] ; } k-- ; double dis = line[0].h ; build(1, NN , 1); double ans = 0 ; for(int i=0;i<NN-1;i++){ int s = find( line[i].l , 0 , k ) ; int e = find( line[i].r , 0 , k ) ; update(1, NN , 1 , s ,e-1, line[i].s ); double dis = line[i].h - line[i+1].h ; ans += dis*sum[1] ; } printf("Test case #%d\n",++cas); printf("Total explored area: %.2lf\n\n",ans); } return 0 ; }