题目简述:输入n个矩形的左下和右上点,求出所有矩阵覆盖的最大面积。
样例输入:
|
样例输出:
|
大致思路:
1)尽管坐标的范围在0-100000;但只有100个点,故应当想到离散化。
2)扫描线,沿y轴向上对平行x轴的线进行操作;
3)update函数的工作是确定两条线之间的有效长度。
4)update函数的工作方式:
从低到高,对橘红色的横线进行update操作:
引入第一条横线时,tree数组的1-3区间flag=1;
引入第二条横线时,tree数组的1-2、3-6区间flag=1,2-3区间flag=2;
引入第三条横线时,tree数组的1-2、3-4、5-6区间flag=1,2-3、4-5区间flag=2;
引入第四条横线时,因为它是出边,故tree数组2-4、5-6区间flag=1,4-5区间flag=2;
第五条,区间4-5的flag=1,其余区间flag为0;
第六条,Tree数组所有区间flag变回0。
值得注意的是,ans是在update操作前进行"+="的,也就是说,本次update后的有效横线长,是为了下一次运算,所以要在循环前先引入第一条边。
AC代码:
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<map>
#define ll long long
using namespace std;
double linex[210],ans;//x轴的值
int n;
map<double,int>xindex;//离散化后x对应的下标
struct node
{
double h;//线的高度
double l;//左端
double r;//右段
int flag;//1为入边,-1为出边
friend bool operator <(node a,node b) {return a.h<b.h;}//线按高度排序
}line[210];//存放线的数组
struct point
{
double key;//节点的值
ll flag;//这个节点区间被覆盖的次数
}tree[840]; //线段数上的节点
void pushup(ll n)//向上更新
{
if(tree[n].flag==0) //若这个区间没被覆盖
tree[n].key=tree[n*2+1].key+tree[n*2].key;
}
void build(ll n, ll l, ll r)//建数的函数
{
tree[n].flag = 0; //覆盖标记置0
if(l+1==r){ //如果左右边界相差1,就是叶子节点了
tree[n].key = 0;
return ;
}
ll mid=(l+r)/2;
build(2*n, l, mid); //建左子树
build(2*n+1, mid, r); //建右子树
pushup(n); //向上更新
}
void update(ll n,ll l,ll r,ll x,ll y,ll val)//对[x,y]区间更新,val=1表示覆盖一次,=-1表示取消一次覆盖
{
if(l+1==r)//如果是叶子节点
{
tree[n].flag+=val;//修改覆盖标记
if(tree[n].flag) tree[n].key=linex[r]-linex[l];//如果被覆盖,修改节点的值
else tree[n].key=0;
return;
}
if(l==x&&r==y) //如果找到当前节点
{
tree[n].flag += val; //修改覆盖标记
if(tree[n].flag) //如果被覆盖
tree[n].key = linex[r]-linex[l]; //节点的值为下标对应的linex数组的值之差
else //如果没被覆盖
pushup(n); //它的值等于左右子区间的值之和
}
else{
ll mid=(l+r)/2;
if(x<mid)
update(2*n, l, mid, x, min(y,mid),val); //在左子树更新
if(y>mid)
update(2*n+1, mid, r, max(x,mid), y,val); //在右子树更新
pushup(n); //向上更新
}
}
int main()
{
int ycnt,xcnt,tcase=0; //ycnt表示线的数量,xcnt表示离散化后x值的数量
double x1,x2,y1,y2;
while(scanf("%d",&n)&&n)
{
build(1,1,n);
ycnt=0;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2) ;
linex[++ycnt]=x1;
line[ycnt].l=x1;
line[ycnt].r=x2;
line[ycnt].h=y1;
line[ycnt].flag=1;
linex[++ycnt]=x2;
line[ycnt].l=x1;
line[ycnt].r=x2;
line[ycnt].h=y2;
line[ycnt].flag=-1;
}
sort(linex+1,linex+ycnt+1);//对x轴的值排序
xcnt=unique(linex+1,linex+1+ycnt)-1-linex;//对x值数组去重
for(int i=1;i<=xcnt;i++)
xindex[linex[i]] = i; //对于x值数组,离散化
sort(line+1,line+ycnt+1); //对线数组由低到高排序
ans=0;
update(1,1,xcnt,xindex[line[1].l],xindex[line[1].r],line[1].flag);//放入第一条线
for(int i=2;i<=ycnt;i++)
{
ans+=tree[1].key*(line[i].h-line[i-1].h);
update(1,1,xcnt,xindex[line[i].l],xindex[line[i].r],line[i].flag);//放入线i
}
printf("Test case #%d\n",++tcase);
printf("Total explored area: %.2lf\n\n",ans); //输出答案
}
return 0;
}