http://poj.org/problem?id=1151
给你n个矩形,求面积并,点范围大,需要离散化
按照套路,先离散化,然后从下往上扫描,每次更新线段树区间,累加面积和。
需要注意的就是,这里的线段树存的不是 整点,而是一段线段
如 1-2-3-4-5
tree[1]存的是点1到点2之间的线段,
其长度为 tree[1+1]-tree[1];
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
const int N = 405 ;
struct node
{
int flag;
double lx,rx,y;
node(){}
node(double a,double b,double c,int d)
{
lx=a,rx=b,y=c,flag=d;
}
bool operator<(node b)const
{
return y<b.y;
}
};
node line[N];
double X[N];
double sum[4*N];
int add[4*N];
void pushup(int i,int l,int r)
{
if (add[i]) sum[i]=X[r+1]-X[l]; //如果整个区间被覆盖,则有效长度为整区间
else if (l==r) sum[i]=0; //如果是add[i]==0且是末区间,则有效长度为0
else sum[i]=sum[i<<1]+sum[i<<1|1]; //否则如果add[i]=0,但不是末区间,则有子区间更新
}
void update(int i, int l, int r, int ql, int qr, int val) //更新区间为qlqr,当前区间为l,r,代表当前区间和的节点为i,更新值为val,
{
if(l > qr || ql > r) //更新区间不在当前区间内
return ;
if(ql<=l&&qr>=r) //要更新的区间把当前区间完全包括,则把当前整个区间+val,然后返回上一层
{
add[i] += val;
pushup(i,l,r);
return ;
} //如果上面没reutrn 表示要往左右儿子区间查询,所以把延迟标记放下去
int mid = (l + r) >> 1;
update(i << 1, l, mid, ql, qr, val);
update(i << 1 | 1, mid + 1, r, ql, qr, val);
pushup(i,l,r);
}
int main()
{
int n ,a,b,i;
int cnt=1;
while(scanf("%d",&n)&&n)
{
memset(add,0,sizeof add);
memset(sum,0,sizeof sum);
double x1,x2,y1,y2;
int num=0;
for (int i=0;i<n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
line[++num]=node(x1,x2,y1,1);
X[num]=x1;
line[++num]=node(x1,x2,y2,-1);
X[num]=x2;
}
sort(line+1,line+1+num); //排序线段
sort(X+1,X+1+num); //离散化数组
int num_x=unique(X+1,X+1+num)-X-1; //去重
double ans=0;
for (int i=1;i<num;i++)
{
int l=lower_bound(X+1,X+1+num_x,line[i].lx)-X;
int r=lower_bound(X+1,X+1+num_x,line[i].rx)-X-1; //线段树每个端点的意义是一段线段而不是点,
update(1,1,num_x,l,r,line[i].flag); //更新扫描线
ans+=sum[1]*(line[i+1].y-line[i].y); //累加答案
}
printf("Test case #%d\n",cnt++);
printf("Total explored area: %.2lf\n\n",ans);
}
}