首先感谢一下 Titanium:http://acm.hdu.edu.cn/showproblem.php?pid=1255 从他的博客中得到了思路
怎么计算出重复的面积。
遇到这个求相交矩形的面积的时候,我第一反应就是将cnt标记下推,然后每次都将标记下推, 最后根据cnt的值来模仿1中求面积的方式来求,然后实现起来很复杂,并且估计会超时,所以就百度寻求了一波帮助。
我们先规定sum2 为 至少出现1次时统计的长度 sum为至少出现2次时的长度
如果某个区间的cnt >= 2 那么 就表示这个这个区间的所有长度都是有效长度, sum就等于这个区间的总长度
当cnt == 1时, 表示这整个区间线段至少出现过一次 并且这个区间内的部分线段可能会出现好多次
这个时候访问这个节点的左子树和右子树的sum2,sum = sum2(左子树)+sum2(右子树)。
因为这个区间的cnt == 1 表示目前这个区间的长度都至少出现过了一次, 由于是区间更新且没有下推cnt标记
如果左子树或右子树上sum2 != 0, 那么表示在左子树或右子树上又出现了一次。
那么子树上的一次+目前区间的一次 就能保证出现两次(及以上)。
(请读者充分理解线段树的区域更新, 如果cnt 上有值的话,那么表示 这个区间被完全覆盖的。
如果区间A被完全覆盖了, 那么会在区间A对应的cnt++, 然后 进行更新和返回(return;)
但是由于不下推, 所以A的左子树或者右子树上的cnt都不会发生变化。所以,如果A的左子树或右子树上
的cnt不为0,那么一定有另一条线扫描到了左子树或者右子数,并且没有完全覆盖区间A。
所以,如果A的cnt == 1并且 A的子树上有值,那么子树上的线段长度和就是至少访问过2次的线段长度和了);
当然 如果 l==r的时候有效长度还是为0的, 因为叶子节点没有长度。
1 #include<iostream> 2 #include<algorithm> 3 #include<iomanip> 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 using namespace std; 7 const int N = 1e4; 8 struct Node 9 { 10 double l, r, h; 11 int d; 12 bool operator < (const Node & x) const 13 { 14 return h < x.h; 15 } 16 }A[N]; 17 double X[N], sum[N], sum2[N]; 18 int cnt[N]; 19 void Build(int l, int r, int rt) 20 { 21 sum2[rt] = 0.0,cnt[rt] = 0, sum[rt] = 0.0; 22 if(l == r) return ; 23 int m = l+r >> 1; 24 Build(lson); 25 Build(rson); 26 } 27 void PushUp(int l, int r, int rt) 28 { 29 if(cnt[rt]) 30 { 31 sum2[rt] = X[r] - X[l-1]; 32 } 33 else if(l == r) sum2[rt] = 0.0; 34 else sum2[rt] = sum2[rt<<1] + sum2[rt<<1|1]; 35 if(cnt[rt] > 1) 36 sum[rt] = X[r] - X[l-1]; 37 else if(l == r) sum[rt] = 0; 38 else if(cnt[rt] == 1) sum[rt] = sum2[rt<<1]+sum2[rt<<1|1]; 39 else sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 40 } 41 void Revise(int L, int R, int C, int l, int r, int rt) 42 { 43 if(L <= l && r <= R) 44 { 45 cnt[rt] += C; 46 PushUp(l,r,rt); 47 return ; 48 } 49 int m = l+r >> 1; 50 if(L <=m) Revise(L,R,C,lson); 51 if(m < R) Revise(L,R,C,rson); 52 PushUp(l,r,rt); 53 } 54 void Add(double l, double r, double h, int d, int i) 55 { 56 A[i].l = l; A[i].h = h; 57 A[i].r = r; A[i].d = d; 58 } 59 int main() 60 { 61 ios::sync_with_stdio(false); 62 cin.tie(0); 63 cout.tie(0); 64 int T, n; 65 cin >> T; 66 while(T-- && cin >> n) 67 { 68 int k = 0; 69 double x1, y1, x2, y2; 70 for(int i = 1; i <= n; i++) 71 { 72 cin >> x1 >> y1 >> x2 >> y2; 73 Add(x1,x2,y1,1,k); 74 X[k++] = x1; 75 Add(x1,x2,y2,-1,k); 76 X[k++] = x2; 77 } 78 sort(X,X+k); 79 sort(A,A+k); 80 int pos = 1; 81 for(int i = 1; i < k; i++) 82 { 83 if(X[i] != X[i-1]) 84 X[pos++] = X[i]; 85 } 86 Build(1,pos,1); 87 double ans = 0; 88 for(int i = 0; i < k-1; i++) 89 { 90 int l = lower_bound(X,X+pos,A[i].l) - X; 91 int r = lower_bound(X,X+pos,A[i].r) - X; 92 Revise(l+1,r,A[i].d,1,pos,1); 93 ans += (A[i+1].h - A[i].h) * sum[1]; 94 } 95 cout << fixed << setprecision(2) << ans+0.0001 << endl;//莫名其妙样例一的时候没有四舍五入上去 96 } //所以补了一点上去就给过了 97 return 0; 98 }