Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.
注意:本题的输入数据较多,推荐使用scanf读入数据.
注意:本题的输入数据较多,推荐使用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 1
Sample Output
7.63 0.00
点更新:
#include <iostream> #include <algorithm> #include <stdio.h> using namespace std; const int maxn=1100; struct LINE { double x, y_down, y_up; int flag; bool operator<(const LINE &a)const ///按照x从小到大的顺序排序 { return x<a.x; } }line[2*maxn]; struct TREE { double x,y_down, y_up; int cover; ///用以表示加进线段树中的线段次数 bool flag; ///标记叶子节点 }tree[maxn*8]; double y[2*maxn]; void build(int i, int l, int r) ///当前节点下标,l , r 线段树建立左右线数组下标 { tree[i].x = -1; //-1表示该区间已经没有线段 tree[i].cover = 0; //表示该区间上有多少条线段;左边线段加进去则++,右边线段加进去则-- tree[i].y_down = y[l]; tree[i].y_up = y[r]; tree[i].flag = false; if(l+1==r) { tree[i].flag = true; //flag==true表示达到了叶子节点 return; } int mid=(l+r)>>1; build(2*i, l, mid); build(2*i+1, mid, r); } double insert(int i, double x, double l, double r, int flag) //flag表示为左边还是右边 { if ( r<=tree[i].y_down || l>=tree[i].y_up ) return 0; if (tree[i].flag) /// 叶子节点 { if (tree[i].cover > 1) /// 该区域的面积存在,且未经计算 { double temp_x = tree[i].x; double ans=( x-temp_x )*(tree[i].y_up - tree[i].y_down); tree[i].cover += flag; tree[i].x = x; //定位上一次的x return ans; } else ///虽然是叶子节点,但是需要更新当前的线段覆盖标记 { tree[i].cover += flag; tree[i].x = x; ///更新最新x return 0; } } return insert(2*i, x, l, r, flag)+insert(2*i+1, x, l, r, flag); ///不是叶子节点就往下递归 } int main( ) { // freopen("d:\\in.txt","r",stdin); int n,index; double x1, y1, x2, y2; int T; scanf("%d",&T); while(T--) { scanf("%d",&n) ; index = 1; for (int i=1; i<=n; i++) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); y[index] = y1; line[index].x = x1; line[index].y_down = y1; line[index].y_up = y2; line[index++].flag = 1; //1表示左边 y[index] = y2; line[index].x = x2; line[index].y_down = y1; line[index].y_up = y2; line[index++].flag = -1; //-1表示右边 } sort(&y[1], &y[index]); //把所有的纵坐标按从小到大排序,把1写成了0,WA一次 sort(&line[1], &line[index]); build(1, 1, index-1); double ans=0; for (int i=1;i<index; i++) ///将线line从左向右遍历 ans+=insert(1, line[i].x, line[i].y_down, line[i].y_up, line[i].flag); printf("%.2f\n", ans); } return 0; }
区间更新:
/* HDU 1255 覆盖的面积 求矩形交的面积(线段树+离散化) 给定一些矩形 被这些矩形覆盖过至少两次的区域的面积 */ #include<stdio.h> #include<iostream> #include<algorithm> using namespace std; #define MAXN 2010 struct Node { int l,r; ///线段树的左右整点 int c; ///c用来记录重叠情况 double lf,rf; ///rf,lf分别是对应的左右真实的浮点数端点 double cnt,more;///cnt是值被覆盖一次以上的长度,more值被覆盖两次以上的长度 }segTree[MAXN*3]; struct Line { double x,y_down,y_up; int flag; }line[MAXN]; ///用来记录重叠情况,可以根据这个来计算,nod节点中的c bool cmp(Line a,Line b)//sort排序的函数 { return a.x < b.x; } double y[MAXN];//记录y坐标的数组 void Build(int t,int l,int r)//构造线段树 { segTree[t].l=l; segTree[t].r=r; segTree[t].cnt=segTree[t].c=0; segTree[t].lf=y[l]; segTree[t].rf=y[r]; if(l+1==r) return; int mid=(l+r)>>1; Build(t<<1,l,mid); Build(t<<1|1,mid,r);//递归构造 } void calen(int t)//计算长度 { if(segTree[t].c>=2) ///该区间被覆盖两次或以上 { segTree[t].more=segTree[t].cnt=segTree[t].rf-segTree[t].lf; return; } else if(segTree[t].c==1) ///该区间被覆盖一次 { segTree[t].cnt = segTree[t].rf-segTree[t].lf; if(segTree[t].l+1==segTree[t].r) segTree[t].more=0; else segTree[t].more = segTree[t<<1].cnt + segTree[t<<1|1].cnt; } else ///该区间 { if(segTree[t].l+1==segTree[t].r) ///子节点 segTree[t].more=segTree[t].cnt=0; else ///非子节点 { segTree[t].cnt=segTree[t<<1].cnt+segTree[ t<<1|1 ].cnt; segTree[t].more=segTree[t<<1].more+segTree[ t<<1|1 ].more; } } } void update(int t,Line line)//加入线段e,后更新线段树 { if( line.y_down==segTree[t].lf && line.y_up==segTree[t].rf ) ///恰好是当前的区间 segTree[t].c += line.flag; else{ if(line.y_up<=segTree[t<<1].rf) ///需要更新的区间在当前节点的左孩子节点中 update(t<<1,line); else if(line.y_down>=segTree[t<<1|1].lf) ///需要更新的区间在当前节点的右孩子节点中 update(t<<1|1,line); else ///横跨左右两个孩子节点 { Line tmp=line; tmp.y_up=segTree[t<<1].rf; update(t<<1,tmp); tmp=line; tmp.y_down=segTree[t<<1].rf; update(t<<1|1,tmp); } } calen(t); } int main() { int i,n,t,T; double x1,y1,x2,y2; scanf("%d",&T); while(T--) { scanf("%d",&n); t=1; for(i=1;i<=n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); line[t].x=x1; line[t].y_down=y1; line[t].y_up=y2; line[t].flag=1; y[t++]=y1; line[t].x=x2; line[t].y_down=y1; line[t].y_up=y2; line[t].flag=-1; y[t++]=y2; } sort(line+1,line+t,cmp); sort(y+1,y+t); Build(1,1,t-1); double res=0; for(i=1;i<t;i++) { update(1,line[i]); res += segTree[1].more*(line[i+1].x-line[i].x); } printf("%.2lf\n",res); } return 0; }