覆盖的面积
給定平面上若干矩形,求出被這些矩形覆蓋過至少兩次的區域的面積.?
?
Input
輸入數據的第一行是一個正整數T(1<=T<=100),代表測試數據的數量.每個測試數據的第一行是一個正整數N(1<=N<=1000),代表矩形的數量,然后是N行數據,每一行包含四個浮點數,代表平面上的一個矩形的左上角坐標和右下角坐標,矩形的上下邊和X軸平行,左右邊和Y軸平行.坐標的范圍從0到100000.?
注意:本題的輸入數據較多,推薦使用scanf讀入數據.?
Output
對于每組測試數據,請計算出被這些矩形覆蓋過至少兩次的區域的面積.結果保留兩位小數.?
Sample Input
2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1Sample Output
7.63 0.00C++版本一
#include <iostream> #include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <math.h> #include <vector>using namespace std;const int N=10000+10; int t,n,cnt=0; double x,x2,y,y2; double tree[N],tree2[N]; int flag[N]; double X[N]; void init(){memset(tree,0.0,sizeof(tree));memset(tree2,0.0,sizeof(tree2));memset(flag,0,sizeof(flag));cnt=0; } struct node{double l,r,y;int s;node(){};node(double l0,double r0,double y0,int s0){l=l0;r=r0;y=y0;s=s0;}bool operator <(const node &S) const{return y<S.y;} }G[N]; void pushup(int i,int l,int r){if(flag[i])tree[i]=X[r+1]-X[l];else if(l==r)tree[i]=0;elsetree[i]=tree[i<<1]+tree[i<<1|1];if(flag[i]>1)tree2[i]=X[r+1]-X[l];else if(l==r)tree2[i]=0;else if(flag[i]==1)tree2[i]=tree[i<<1]+tree[i<<1|1];elsetree2[i]=tree2[i<<1]+tree2[i<<1|1];} void updata(int i,int l,int r,int L,int R,int C){if(L<=l&&r<=R){flag[i]+=C;pushup(i,l,r);return;}int m=(l+r)>>1;if(R<=m)updata(i<<1,l,m,L,R,C);else if(m<L)updata(i<<1|1,m+1,r,L,R,C);else{updata(i<<1,l,m,L,m,C);updata(i<<1|1,m+1,r,m+1,R,C);}pushup(i,l,r); } int main() {scanf("%d",&t);for(int i=1;i<=t;i++){init();scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%lf%lf%lf%lf",&x,&y,&x2,&y2);G[++cnt]=node(x,x2,y,1);X[cnt]=x;G[++cnt]=node(x,x2,y2,-1);X[cnt]=x2;}sort(X+1,X+cnt+1);sort(G+1,G+cnt+1);int k=1;for(int i=2;i<=cnt;i++){if(X[i]!=X[i+1]) X[++k]=X[i];}double ans=0;for(int i=1;i<cnt;i++){int l=lower_bound(X+1,X+k+1,G[i].l)-X;int r=lower_bound(X+1,X+k+1,G[i].r)-X-1;//cout << tree[1] << endl;updata(1,1,k,l,r,G[i].s);ans+=tree2[1]*(G[i+1].y-G[i].y);}printf("%.2f\n",ans+0.0001);}//cout << "Hello world!" << endl;return 0; }C++版本二
首先感謝一下 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的, 因為葉子節點沒有長度。
https://www.cnblogs.com/MingSD/p/8393274.html
#include<iostream> #include<algorithm> #include<iomanip> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int N = 1e4; struct Node {double l, r, h;int d;bool operator < (const Node & x) const{return h < x.h;} }A[N]; double X[N], sum[N], sum2[N]; int cnt[N]; void Build(int l, int r, int rt) {sum2[rt] = 0.0,cnt[rt] = 0, sum[rt] = 0.0;if(l == r) return ;int m = l+r >> 1;Build(lson);Build(rson); } void PushUp(int l, int r, int rt) {if(cnt[rt]){sum2[rt] = X[r] - X[l-1];}else if(l == r) sum2[rt] = 0.0;else sum2[rt] = sum2[rt<<1] + sum2[rt<<1|1];if(cnt[rt] > 1)sum[rt] = X[r] - X[l-1];else if(l == r) sum[rt] = 0;else if(cnt[rt] == 1) sum[rt] = sum2[rt<<1]+sum2[rt<<1|1];else sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void Revise(int L, int R, int C, int l, int r, int rt) {if(L <= l && r <= R){cnt[rt] += C;PushUp(l,r,rt);return ;}int m = l+r >> 1;if(L <=m) Revise(L,R,C,lson);if(m < R) Revise(L,R,C,rson);PushUp(l,r,rt); } void Add(double l, double r, double h, int d, int i) {A[i].l = l; A[i].h = h;A[i].r = r; A[i].d = d; } int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int T, n;cin >> T;while(T-- && cin >> n){int k = 0;double x1, y1, x2, y2;for(int i = 1; i <= n; i++){cin >> x1 >> y1 >> x2 >> y2;Add(x1,x2,y1,1,k);X[k++] = x1;Add(x1,x2,y2,-1,k);X[k++] = x2;}sort(X,X+k);sort(A,A+k);int pos = 1;for(int i = 1; i < k; i++){if(X[i] != X[i-1])X[pos++] = X[i];}Build(1,pos,1);double ans = 0;for(int i = 0; i < k-1; i++){int l = lower_bound(X,X+pos,A[i].l) - X;int r = lower_bound(X,X+pos,A[i].r) - X;Revise(l+1,r,A[i].d,1,pos,1);ans += (A[i+1].h - A[i].h) * sum[1];}cout << fixed << setprecision(2) << ans+0.0001 << endl;//莫名其妙樣例一的時候沒有四舍五入上去} //所以補了一點上去就給過了return 0; }?
總結