覆盖的面积 HDU - 1255(线段树,扫描线)

覆盖的面积

题目链接:HDU - 1255

题意:若干矩形重叠在一起,求出重叠部分的面积之和,如下图,求出红色区域面积;

之前算过整个图形的面积,而今要算重叠部分的面积,还是原来的思路,接着动用那条墨绿的扫描线;

和之前有些许不同的是扫描线要扫过两次才能出现重叠区域,那么如何用线段树维护区间[l, r]被覆盖次数大于1的长度呢?

先回想一下用线段树维护区间[l, r]被覆盖的长度的算法:

分三种情况:

一:[l, r]被完全覆盖,len=r+1-l;(线段存入线段树的不同点,[l, r]存入线段树时存入的是[l, r-1]);

二:[l, r]是个叶子,len=0;

三:[l, r]未被完全覆盖,len=左右子区间被覆盖长度和;

那么维护区间[l, r]被覆盖次数大于1的长度能不能同样的分为三部分呢?

一:[l, r]全部被覆盖2次及以上,len=r+1-l;

二:[l, r]是个叶子, len=0;

三:[l, r]没有全部被覆盖2次及以上;这时就不一样了,还能在分成两种情况:

3.1:[l, r]全部被覆盖,但只有部分是被覆盖2次及以上, len=左右子区间被覆盖1次及以上长度之和;why?如果之前子区间已经被覆盖了1次了,那么来到父区间,不久又被覆盖了一次嘛,所以得出结果;

3.2:[l, r]只有部分被覆盖,len=左右子区间被覆盖2次及以上长度之和;这里就比较好理解了;

综上所述,求区间[l, r]被覆盖两次及以上长度分为四种情况;

#include <bits/stdc++.h>
using namespace std;
const int maxn=1010;
struct Line{
	double y, x1, x2;
	int v;
	Line(){}
	Line(double y0, double x10, double x20, int v0){
		y=y0, x1=x10, x2=x20, v=v0;
	}
	bool operator < (const Line &p) const {
		return y<p.y;
	}
}line[maxn<<1];
double x[maxn<<1];
int cnt_l, cnt_x;
struct node{
	int l, r, v;
   	double len1, len2;
}tr[maxn<<3];
void build(int m, int l, int r){
	tr[m].l=l;
	tr[m].r=r;
	tr[m].v=0;
	tr[m].len1=tr[m].len2=0.0;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(m<<1, l, mid);
	build(m<<1|1, mid+1, r);
}
void pushup(int m){
	if(tr[m].v){
		tr[m].len1=x[tr[m].r+1]-x[tr[m].l];
	}else if(tr[m].l==tr[m].r){
		tr[m].len1=0;
	}else{
		tr[m].len1=tr[m<<1].len1+tr[m<<1|1].len1;
	}
	if(tr[m].v>1){
		tr[m].len2=x[tr[m].r+1]-x[tr[m].l];
	}else if(tr[m].l==tr[m].r){
		tr[m].len2=0;
	}else if(tr[m].v==1){
		tr[m].len2=tr[m<<1].len1+tr[m<<1|1].len1;
	}else{
		tr[m].len2=tr[m<<1].len2+tr[m<<1|1].len2;
	}
}
void updata(int m, int l, int r, int v){
	if(tr[m].l==l&&tr[m].r==r){
		tr[m].v+=v;
		pushup(m);
		return;
	}
	int mid=(tr[m].l+tr[m].r)>>1;
	if(r<=mid) updata(m<<1, l, r, v);
	else if(l>mid) updata(m<<1|1, l, r, v);
	else{
		updata(m<<1, l, mid, v);
		updata(m<<1|1, mid+1, r, v);
	}
	pushup(m);
}
int main(){
	int T;
	double x1, x2, y2, y1;
	scanf("%d", &T);
	while(T--){
		int n;
		scanf("%d", &n);
		cnt_l=cnt_x=0;
		for(int i=0; i<n; i++){
			scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
			x[++cnt_x]=x1;
			x[++cnt_x]=x2;
			line[++cnt_l]=Line(y1, x1, x2, 1);
			line[++cnt_l]=Line(y2, x1, x2, -1);
		}
		sort(line+1, line+1+cnt_l);
		sort(x+1, x+1+cnt_x);
		cnt_x=unique(x+1, x+1+cnt_x)-(x+1);
		build(1, 1, cnt_x);
		double ans=0.0;
		for(int i=1; i<=cnt_l; i++){
			int l=upper_bound(x+1, x+1+cnt_x, line[i].x1)-(x+1);
			int r=upper_bound(x+1, x+1+cnt_x, line[i].x2)-(x+1)-1;
			updata(1, l, r, line[i].v);
			ans+=(line[i+1].y-line[i].y)*tr[1].len2;
		}

		printf("%.2lf\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sirius_han/article/details/81094408