题意:给出多个矩形的左上角和右下角坐标,求这些矩形面积的并,即相重的面积只算一次

解题思路:
首先离散化:把读进来的坐标变为一条竖边,一个矩形有两个竖边:左竖边和右竖边,左竖边用与制造覆盖,右竖边用于消除覆盖,要标记好哪些是左竖边,哪些是右竖边。建一个结构体数组来存放竖边,并按照竖边的很坐标升序排序(从小到大)。
把所有的纵坐标用一个数组存放,并升序排序,离散化结束。

建一个线段树用于查看目前那些纵坐标被覆盖了,从而计算当前的被覆盖纵坐标长度。结合竖边的左右性质就能不断更新线段树,从而计算新的矩形。
数据很水。

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;
}