HDU1255 Find the scan line of a rectangular area that covers twice or more

The two coverages are not only to change the judgment conditions of cnt,
but to discuss, even though there is only one layer of mark or no mark, it may still contribute to the current situation.
That is:
discussion by situation
1.cnt>1: explain the interval If it is covered twice or more, then the length can be directly calculated, which is the length of the interval, and the rest is cnt=1 or cnt=0
2. First look at the leaf node, because the leaf has no children, it is covered by two The length above the inferior goods is 0 (whether cnt=1 or cnt=0 is 0, because it is a leaf...)
3. It is not a leaf node, and cnt=1. Note here, what exactly is the meaning of cnt=1, It should be, it can be determined that this interval is completely covered once, but whether it is completely covered twice or more is not sure, so what should be done, just add t[lch].s + t[rch ].s That is, look at the length of the left and right child interval being covered once or more, then superimposed on the parent is the length of the parent being covered twice or more
3. Not a leaf node, and cnt=0, the exact meaning should be I don’t know the situation of being covered (I don’t know if it has been covered, how many times it has been covered, and how long it is). In this case, it can only be obtained from the information about the child
t[lch].ss + t[rch].ss, that is, directly add the length of the left and right children covered two or more times, so as to avoid repetition and omission.
From https://www.cnblogs.com/scau20110726/archive/2013/04 /14/3020998.html

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 1e5+7;
struct node
{
    
    
	double l,r,h;
	int f;//l线段左端点 r右端点 h高度 f标记当前这条线段是矩形的上边界还是下边界
}line[MAXN];
double lsh[MAXN];
double tree[MAXN][3];
int ct[MAXN];
int n;
bool cmp(node a,node b){
    
    
	return a.h < b.h;
}
//如果单纯的 只考虑 ct>1的情况 会漏掉很多面积 要分类讨论才不会少
// 通过分类讨论的思想也就可以类似的求 三次 四次的面积 都是可以推得的
void pushup(int rt,int l,int r)
{
    
    
	// 先把一次的更新了
	if(ct[rt]) tree[rt][1] = lsh[r+1]-lsh[l];
	else if(l == r) tree[rt][1] = 0;
	else tree[rt][1] = tree[rt<<1][1]+tree[rt<<1|1][1];
	//再更新两次的
	if(ct[rt]>1) tree[rt][2] = tree[rt][1];
	else if(l == r) tree[rt][2] = 0;
	else if(ct[rt] == 1) tree[rt][2] = tree[rt<<1][1]+tree[rt<<1|1][1];// 当前只覆盖一次 但之前的子孙可能被完全覆盖过 加起来刚好两次
	else tree[rt][2] = tree[rt<<1][2]+tree[rt<<1|1][2];
}

void build(int rt,int l,int r)
{
    
    
	tree[rt][1] = tree[rt][2] = 0;
	ct[rt] = 0;
	if(l == r) return ;
	int mid = (l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
}

void update(int rt,int l,int r,int ul,int ur,int x)
{
    
    
	if(l>=ul&&r<=ur){
    
    
		ct[rt] += x;
		pushup(rt,l,r);//覆盖标记发生了变化 因此需要 下推一下 重新复值
		return ;
	}
	int mid = (l+r)>>1;
	if(ul <= mid) update(rt<<1,l,mid,ul,ur,x);
	if(ur > mid) update(rt<<1|1,mid+1,r,ul,ur,x);
	pushup(rt,l,r);
}

int main()
{
    
    
	int cas = 0;
	int t;
	scanf("%d",&t);
	double x1,x2,y1,y2;
	while(t--){
    
    
		int n;
		scanf("%d",&n);
		int cnt = 0;
		for(int i = 1;i <= n;i ++){
    
    
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			lsh[++cnt] = x1;//因为坐标会有小数 所以需要离散化 才能用线段树维护
			line[cnt].l = x1;
			line[cnt].r = x2;
			line[cnt].h = y1;
			line[cnt].f = 1;//因为要从下往上扫 所以把下面的当做1
			lsh[++cnt] = x2;
			line[cnt].l = x1;
			line[cnt].r = x2;
			line[cnt].h = y2;
			line[cnt].f = -1;
		}
		sort(lsh+1,lsh+cnt+1);
		sort(line+1,line+cnt+1,cmp);
		int num = unique(lsh+1,lsh+1+cnt)-lsh-1;
		//printf("%d\n",num);
		build(1,1,num);
		double ans = 0;
		for(int i = 1;i <= cnt;i ++){
    
    
			int l = lower_bound(lsh+1,lsh+1+num,line[i].l)-lsh;
			int r = lower_bound(lsh+1,lsh+1+num,line[i].r)-lsh-1;
			//printf("%d %d\n",l,r);
			update(1,1,num,l,r,line[i].f);
			ans += tree[1][2]*(line[i+1].h-line[i].h);// tree[1]代表走到当前节点 被覆盖的区间的总长度为多少
		}
		printf("%.2f\n",ans);
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45672411/article/details/107222739