覆盖的面积[矩形面积并]

文章目录

题目

HDU
在这里插入图片描述

思路

主要是这里的线段树要搞清楚只能查询区间 [ 1 , q ] [1,q] [1,q] (最大的区间)
这里的标记不下传的特殊性
因为要解决 次 数 ≥ 2 次数\ge 2 2 很难进行区间减操作
u . s 1 : u.s_1: u.s1: 只考虑 u u u 子树内恰好被覆盖一次长度
u . s 2 : u.s_2: u.s2: 只考虑 u u u 子树内被覆盖至少两次长度
更新如下

void PushUp(int u){//有点不严谨,没有考虑叶节点赋值情况
	if(t[u].cnt>=2)
		t[u].s1=t[u].s2=t[u].s0;
	else if(t[u].cnt==1){
		t[u].s1=t[u].s0;
		t[u].s2=t[lch].s1+t[rch].s1;
	}
	else{
		t[u].s1=t[lch].s1+t[rch].s1;
		t[u].s2=t[lch].s2+t[rch].s2;
	}
	return ;
}

代码

#include<set>  
#include<map>  
#include<stack>  
#include<cmath>  
#include<cstdio>  
#include<queue>  
#include<vector>  
#include<climits>  
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;     
int read(){     
    int f=1,x=0;char s=getchar();        
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}       
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}     
    return x*f;    
}
const int MAXN=100000;
const int INF=0x3f3f3f3f;
struct node{
	int cnt;
	double s0,s1,s2;
}t[5*MAXN+5];
#define lch (u<<1)
#define rch (u<<1|1)
struct mo{int l,r,c;};
vector<mo> G[MAXN+5];
double X1[MAXN+5],X2[MAXN+5],Y1[MAXN+5],Y2[MAXN+5];
double Dx[2*MAXN+5],Dy[2*MAXN+5];
void BS(double *A,int len,double &x){
	int L=1,R=len+1;
	while(L+1<R){
		int Mid=(L+R)>>1;
		if(A[Mid]<=x) L=Mid;
		else R=Mid;
	}
	x=L;
	return ;
}
double val[MAXN+5];
void PushUp(int u){
	if(t[u].cnt>=2)
		t[u].s1=t[u].s2=t[u].s0;
	else if(t[u].cnt==1){
		t[u].s1=t[u].s0;
		t[u].s2=t[lch].s1+t[rch].s1;
	}
	else{
		t[u].s1=t[lch].s1+t[rch].s1;
		t[u].s2=t[lch].s2+t[rch].s2;
	}
	return ;
}
void Build(int u,int L,int R){
	t[u]=(node){0,Dy[R+1]-Dy[L],0,0};
	if(L==R) return ;
	int Mid=(L+R)>>1;
	Build(lch,L,Mid),Build(rch,Mid+1,R);
	PushUp(u);
	return ;
}
void Modify(int u,int L,int R,int qL,int qR,int p){
	if(qL<=L&&R<=qR){
		t[u].cnt+=p,PushUp(u);
		return ;
	}
	int Mid=(L+R)>>1;
	if(qL<=Mid)
		Modify(lch,L,Mid,qL,qR,p);
	if(Mid+1<=qR)
		Modify(rch,Mid+1,R,qL,qR,p);
	PushUp(u);
	return ;
}
int main(){
	int T=read();
	while(T--){
		int n=read();
		for(int i=1;i<=n;i++){
			scanf("%lf%lf%lf%lf",&X1[i],&Y1[i],&X2[i],&Y2[i]);
			Dx[(i<<1)-1]=X1[i],Dx[(i<<1)]=X2[i],Dy[(i<<1)-1]=Y1[i],Dy[(i<<1)]=Y2[i];
		}
		sort(Dx+1,Dx+2*n+1);
		sort(Dy+1,Dy+2*n+1);
		int p=unique(Dx+1,Dx+2*n+1)-(Dx+1);
		int q=unique(Dy+1,Dy+2*n+1)-(Dy+1);
		for(int i=1;i<=n;i++){
			BS(Dx,p,X1[i]),BS(Dx,p,X2[i]);
			BS(Dy,q,Y1[i]),BS(Dy,q,Y2[i]);
			G[(int)X1[i]].push_back((mo){(int)Y1[i],(int)Y2[i]-1,1});
			G[(int)X2[i]].push_back((mo){(int)Y1[i],(int)Y2[i]-1,-1});
		}
		Build(1,1,q-1);
		double ans=0;
		for(int i=1;i<=p;i++){
			ans+=(Dx[i]-Dx[i-1])*t[1].s2;
			for(int j=0;j<(int)G[i].size();j++)
				Modify(1,1,q-1,G[i][j].l,G[i][j].r,G[i][j].c);
		}
		for(int i=1;i<=p;i++)
			G[i].clear();
		printf("%.2f\n",ans);
	}
    return 0;
}
/*
1
2
1 2 3 4
2 1 4 3

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值