题意:给出多个矩形的左上角和右下角坐标,求这些矩形面积的并,即相重的面积只算一次
解题思路:
首先离散化:把读进来的坐标变为一条竖边,一个矩形有两个竖边:左竖边和右竖边,左竖边用与制造覆盖,右竖边用于消除覆盖,要标记好哪些是左竖边,哪些是右竖边。建一个结构体数组来存放竖边,并按照竖边的很坐标升序排序(从小到大)。
把所有的纵坐标用一个数组存放,并升序排序,离散化结束。
建一个线段树用于查看目前那些纵坐标被覆盖了,从而计算当前的被覆盖纵坐标长度。结合竖边的左右性质就能不断更新线段树,从而计算新的矩形。
数据很水。
0msC++代码
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath> using namespace std; const int NUM = 100005; typedef struct line { int x,y1,y2,flag; }; typedef struct node { int left,mid,right,key,len; }node; line lines[NUM]; node T[ NUM<<2 ]; int Y[NUM];//存储离散化的纵坐标 void create(int u,int l,int r) { T[u].left = l; T[u].right = r; T[u].key = 0; T[u].len = 0; T[u].mid = (l+r)>>1; if(r == l + 1) return; create(u+u,l,T[u].mid); create(u+u+1,T[u].mid,r); } int inquiry(int i) { if(T[i].key > 0) //有覆盖 { return (T[i].len = Y[T[i].right] - Y[T[i].left]); } else if (T[i].right - T[i].left == 1) { return (T[i].len = 0); } // 其他情况 else { return (T[i].len = T[i+i].len + T[i+i+1].len); } } void change(line li,int i)//order为要修改的序号 { if (Y[T[i].left] == li.y1 && Y[T[i].right] == li.y2) { // “左”边flag是1 “右”边flag是-1 // 其实是计算完一个矩形的面积之和,key减去1 // 就相当于把这个矩形擦除掉了 T[i].key += li.flag; } else { int m = (T[i].left + T[i].right) >> 1; if (li.y1 >= Y[m]) { change(li, i+i+1); } else if (li.y2 <= Y[m]) { change(li, i+i); } else { line ll, lr; ll.y1 = li.y1; ll.y2 = Y[m]; ll.flag = li.flag; lr.y1 = Y[m]; lr.y2 = li.y2; lr.flag = li.flag; change(ll, i+i); change(lr, i+i+1); } } // 每次插入节点后,计算覆盖的长度 inquiry(i); } bool cmp(const line& lhs, const line& rhs) { return lhs.x < rhs.x; } int main() { int x1,y1,x2,y2,end=0,n; while(1) { int i = 1; while(scanf("%d %d %d %d",&x1,&y1,&x2,&y2)) { if(x1 == -1 && x2 == -1 && y1 == -1 && y2 == -1) break; if(x1 == -2 && x2 == -2 && y1 == -2 && y2 == -2) { end = 1; break; } if (y1 > y2) { swap(y1, y2); } // 左边的边横坐标是x1,所以x1必须是小的一个 if (x1 > x2) { swap(x1, x2); } lines[i].x = x1; lines[i].y1 = y1; lines[i].y2 = y2; lines[i].flag = 1; Y[i++] = y1; lines[i].x = x2; lines[i].y1 = y1; lines[i].y2 = y2; lines[i].flag = -1; // 抵消上次的覆盖 Y[i++] = y2; } n = i-1; sort(Y+1,Y+n+1); sort(lines+1,lines+n+1,cmp); create(1,1,n); change(lines[1],1); int ans = 0; for(i = 2; i <= n ; i++) { ans += T[1].len * (lines[i].x - lines[i-1].x); change(lines[i],1); } printf("%d\n", ans); if(end) break; } return 0; }