Area covered by (HDU - 1255) (scan line)

Posted by wherertheskips on Thu, 03 Feb 2022 02:01:39 +0100

Given several rectangles on the plane, find the area of the area covered by these rectangles at least twice

Input

Lower left and upper right coordinates

The first line of input data is a positive integer t (1 < = T < = 100), representing the number of test data The first row of each test data is a positive integer N (1 < = N < = 1000), representing the number of rectangles, and then N rows of data. Each row contains four floating-point numbers, representing the coordinates of the lower left corner and the upper right corner of a rectangle on the plane. The upper and lower edges of the rectangle are parallel to the X axis, and the left and right sides are parallel to the Y axis The coordinates range from 0 to 100000  
Note: there are many input data in this question. It is recommended to use scanf to read the data  

Output

For each set of test data, please calculate the area covered by these rectangles at least twice Keep the result to two decimal places  
 

Sample Input

2
5
1 1 4 2
1 3 3 7
2 1.5 5 4.5
3.5 1.25 7.5 4
6 3 10 7
3
0 0 1 1
1 0 2 1
2 0 3 1

Sample Output

7.63
0.00

This problem is still solved by scanline. If you don't understand the principle of scanline, you can read my previous blog and attach the address of scanline blog below: Paint area (scan line)_ AC__dream blog - CSDN blog

The topic of paint area is to find the area of the union of rectangles, and this topic is to find the area of the intersection of rectangles. The principle is basically the same. In the topic of paint area, we maintain the maximum length of covering a section at least once, and this problem obviously can't only maintain this one, If you think about it carefully, it's easy to think that this problem requires us to maintain the maximum length of covering a section at least twice, because the area itself is the integral of the line segment. When the line segment is covered only once, the integrated area will be covered only once, and when the line segment is covered multiple times, the integrated area will be covered multiple times, Speaking of this, the idea of this topic is relatively clear. Let me talk about how to calculate the maximum length covered twice in the interval.

First, let's review how to calculate the maximum length covered at least once: (it needs to be reminded again that the point interval [l,r] represents the distance between the L-th point and the r+1 point)

First, if the current interval is covered once as a whole, it is obvious that the maximum length of the interval covered at least once is the length of the interval itself. If the current interval is not covered once, there are two clear situations. One is that the current interval is a point, and the actual length is 1, Then it is certain that the maximum length of the interval with length one covered at least once is 0. When the interval is an interval with length and length not 1, the maximum length of the interval covered at least once is the sum of the maximum length of the interval covered at least once of the left and right sub intervals of the interval. Here is the code of this part:

void pushup(int id)
{
    if(cnt[id])     len[id]=alls[r[id]]-alls[l[id]-1];// Point interval [l[id],r[id]] actually represents segment interval [all [l [ID] - 1], all [R [ID]]]
    else if(l[id]==r[id]) len[id]=0;
    else len[id]=len[id<<1]+len[id<<1|1];
}

Here's how to calculate the maximum length of being covered at least twice:

Firstly, if the current interval is covered twice as a whole, it is obvious that the maximum length of the interval covered at least twice is the length of the interval itself. Moreover, if the current interval is a point, the actual length is 1. It is certain that the maximum length of the interval covered at least twice with a length of one is 0, which is relatively easy to get, Next, there are two cases. The interval length represented by these two cases is not 1. One is that the number of times the current length is covered is 1. Since we did not update the child node through the parent node when updating the segment tree, the maximum length covered by the child interval of the current interval is independent of the current interval, Then, the maximum length of the current interval covered at least twice is the sum of the interval lengths of the left and right sub intervals covered at least once. In addition, the current interval has been completely covered once, so the public part is covered at least twice. This place is prone to errors. We must understand it well. The following is the last case, that is, the number of times the current length is covered is 0, There's nothing to consider. It's the sum of the length of the interval where the left and right intervals are covered at least twice.

Corresponding code (this code is a combined code that updates the longest length of the interval covered at least once and the longest length of the interval covered at least twice):

void pushup(int id)
{
/ / find the length of the longest interval whose coverage times are greater than or equal to 1
    if(cnt[id]) len[id]=alls[r[id]]-alls[l[id]-1];
    else if(l[id]==r[id]) len[id]=0;
    else len[id]=len[id<<1]+len[id<<1|1];
/ / find the length of the longest interval whose coverage times are greater than or equal to 2
    if(cnt[id]>=2)  len2[id]=alls[r[id]]-alls[l[id]-1];
    else if(l[id]==r[id]) len2[id]=0;
    else if(cnt[id]==1) len2[id]=len[id<<1]+len[id<<1|1];// If the current interval is covered once, the maximum length of the current interval covered twice is the sum of the maximum lengths of the left and right intervals covered once or more
    else len2[id]=len2[id<<1]+len2[id<<1|1];
}

Another thing that needs special attention is rounding. Pay attention to the accuracy

The following code is:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=1e4+10;
int l[N],r[N],cnt[N];//cnt[i] record the number of times the i-th interval is covered 
double len[N],len2[N];//len[i] records the maximum length in which the i-th interval is covered more than or equal to 1, and len2[i] records the maximum length in which the i-th interval is covered more than or equal to 2
vector<double>alls;
struct node{
	double x,yn,yx;
	int k;
}p[N];
bool cmp(node a,node b)
{
	return a.x<b.x;
}
double find(double x)
{
	return lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1;
}
void pushup(int id)
{
	//Find the longest interval length with coverage times greater than or equal to 1 
	if(cnt[id]) len[id]=alls[r[id]]-alls[l[id]-1];
	else if(l[id]==r[id]) len[id]=0;
	else len[id]=len[id<<1]+len[id<<1|1];
	//Find the longest interval length with coverage times greater than or equal to 2
	if(cnt[id]>=2)  len2[id]=alls[r[id]]-alls[l[id]-1];
	else if(l[id]==r[id]) len2[id]=0;
	else if(cnt[id]==1) len2[id]=len[id<<1]+len[id<<1|1];//If the current interval is covered once, the maximum length of the current interval covered twice is the sum of the maximum lengths of the left and right intervals covered once or more 
	else len2[id]=len2[id<<1]+len2[id<<1|1];
}
void build(int id,int L,int R)
{
	l[id]=L;r[id]=R;cnt[id]=len[id]=0;
	if(L==R) return ;
	int mid=L+R>>1;
	build(id<<1,L,mid);
	build(id<<1|1,mid+1,R);
}
void update_interval(int id,int L,int R,int k)
{
	if(l[id]>=L&&r[id]<=R)//The current interval is completely in the target interval 
	{
		cnt[id]+=k;
		pushup(id);
		return ;
	}
	int mid=l[id]+r[id]>>1;
	if(mid>=L) update_interval(id<<1,L,R,k);
	if(mid+1<=R) update_interval(id<<1|1,L,R,k);
	pushup(id);
}
int main()
{
	int T,n;
	cin>>T;
	while(T--)
	{
		scanf("%d",&n);
		double x1,y1,x2,y2;
		int cnt=0;
		alls.clear();
		for(int i=1;i<=n;i++)
		{
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			p[++cnt]={x1,y1,y2,1};
			p[++cnt]={x2,y1,y2,-1};
			alls.push_back(y1);
			alls.push_back(y2);
		}
		sort(p+1,p+cnt+1,cmp);
		sort(alls.begin(),alls.end());
		alls.erase(unique(alls.begin(),alls.end()),alls.end());
		for(int i=1;i<=cnt;i++)
		{
			p[i].yn=find(p[i].yn);
			p[i].yx=find(p[i].yx);
		}
		build(1,1,alls.size());
		double ans=0;
		for(int i=1;i<=cnt;i++)
		{
			if(i>1) ans+=len2[1]*(p[i].x-p[i-1].x);
			update_interval(1,(int)p[i].yn,(int)p[i].yx-1,p[i].k);
		}
		printf("%.2lf\n",ans+0.0001);
	}
	return 0;
}

Topics: data structure