HDU 1542
- 一条竖直直线从左到右(反向也行)扫描,那么将扫描出来的直线的y坐标离散化,然后用线段树维护
y
轴的覆盖区间.x
值作为高度 - 如果一条横着直线从下到上(反向也行)扫描,将扫描出来的x坐标离散化,线段树维护
x
轴的覆盖区间,y
作为高度. - 此题从上到下扫,将
x
坐标离散化,建树 - 将一个矩形的2条边标记为上边1和下边-1,用线段树维护时不需要延迟标记,因为成对出现,下一次对应边出现就会消去此次覆盖.
- 但是线段树端点出问题,一条上边
[1,3]
,一条下边[3,5]
,3
最后覆盖值为0
,就会少算一个覆盖点,方法:线段树的右端都-1变成[1,2] [3,4]
, - 线段树节点维护2个信息,
sum[]
:覆盖长度,add[]
:节点被覆盖的次数,
add>0
,该节点的sum = x[right+1] - x[left]
add = 0
,该节点没有被覆盖,那么覆盖区间是子节点的覆盖区间:sum=sum[2*p]+sum[2*p+1]
#include <iostream>
#include <string.h>
#include <algorithm>
#define lson p<<1,left,mid
#define rson p<<1|1,mid+1,right
using namespace std;
const int maxn = 2000+5;
int add[maxn << 2];
double x[maxn<<2],sum[maxn<<2];
int n, cnt, res;
struct node {
double l, r, h;
int s;
node() {};
node(double ll,double rr,double hh,int ss) {
l = ll; r = rr; h = hh; s = ss;
}
bool operator<(const node& temp)const {
return h < temp.h;
}
}s[maxn];
void pushup(int p,int left,int right) {
if (add[p]) sum[p] = x[right + 1] - x[left]; //得到长度
else if (left == right) sum[p] = 0; //[x[right+1],x[left]],由于没有覆盖所以=0
else sum[p] = sum[p << 1] + sum[p<<1|1];//向上更新长度
}
void updata(int L,int R,int val,int p,int left,int right) {
if (L <= left && right <= R) {
add[p] += val;
pushup(p,left,right);
return;
}
int mid = (left + right) >>1;
if (L <= mid) updata(L,R,val,lson);
if (mid < R) updata(L,R,val,rson);
pushup(p,left,right);
}
//int binary_find(double val) {
// int left = -1, right = res - 1;
// while (right - left > 1) {
// int mid = (left + right)>>1;
// if (x[mid] >= val) right = mid;
// else left = mid;
// }
// return right;
//}
int binary_find(double val) {
int left = 0, right = res - 1;
while (left <= right) {
int mid = (left + right) >> 1;
if (x[mid] < val) left = mid + 1;
else right = mid - 1;
}
return left;
}
int main() {
int count = 1; //freopen("a.txt","r",stdin);
while (scanf("%d",&n) != EOF && n) {
cnt = 0;
for (int i = 0; i < n; i++) {
double a, b, c, d;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d); //a,b是左上角的点, c,d,是右上角的点
s[cnt] = node(a,c,b,1);
x[cnt++] = a; //横坐标存下来,进行离散化
s[cnt] = node(a,c,d,-1);
x[cnt++] = c;
}
sort(s,s+cnt); //扫描线按高度排序
sort(x,x+cnt); //离散化的坐标进行排序
res=1; //去重的辅助标记
for (int i = 1; i < cnt; i++)
if (x[i] != x[i - 1]) x[res++] = x[i];//将相同的去重,移到前面去
memset(add,0,sizeof add);
memset(sum,0,sizeof sum);
double ans = 0;
for (int i = 0; i < cnt-1; i++) {
int l = binary_find(s[i].l);
int r = binary_find(s[i].r) - 1; //在x中找到离散后的坐标
updata(l,r,s[i].s,1,0,res-1); //res是去重后坐标的总数+1
ans += sum[1] * (s[i+1].h - s[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n", count++, ans);
}
return 0;
}