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

传送门
求面积的交.
做法应该不难想到,用扫描线维护被覆盖了两次的线段长度.
面积的并的做法应该不陌生.维护覆盖一次的线段长度就ok了.没做过的可以看这篇博客的后面关于扫描线算法的讲解.
扫描线使用的线段树和平时使用的线段树有一个比较特殊的地方.维护矩形的时候总是有一个相同范围的入边和出边.所以我们可以不打lazy标记,直接只对[l,r]区间操作.打了lazy标记反而会不太好.因为覆盖的长度是底层往上统计的.如果打lazy标记的话无法得到正确的答案.要是想得到正确的答案的话就要遍历所有跟节点了.复杂度也就不优秀了.变成了O(n^2)了.所以一般不打lazy标记.(这只是我对扫描线的一点拙见…毕竟也就只写过5.6题…说的不对望指正)

所以这题的做法也一样,不打lazy标记.只统计覆盖次数就好了.同时把len变量换成两个len1,len2记录被覆盖一次和两次的线段长度.这样子就可以直接统计长度了.这个区间如果只被覆盖一次,那么它被覆盖两次的长度就是左右区间被覆盖一次长度的和.

代码

#pragma GCC optimize(2)
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define afir(i,a,b) for(int i=a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define L 2*i
#define R 2*i+1
#define ALL(a) a.begin(),a.end()
#define bug puts("--------")
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
struct Point{
	double x,y1,y2;
	int k;
	bool operator<(const Point&w)const{
		if(x == w.x) return k > w.k;
		return x < w.x;
	}
}p[N*2];
struct Tree{
	int l,r,cnt,lz;
	double len1,len2;
}tree[N*4];
vector<double> all;
int getpos(double x){
	return lower_bound(ALL(all),x) - all.begin();
}
void getlen(int i){
	if(tree[i].cnt >= 2) tree[i].len2 = all[tree[i].r+1] - all[tree[i].l];
	else if(tree[i].cnt == 1) tree[i].len2 = tree[L].len1 + tree[R].len1;
	else tree[i].len2 = tree[L].len2 + tree[R].len2;
	if(tree[i].cnt >= 1) tree[i].len1 = all[tree[i].r+1]-all[tree[i].l];
	else tree[i].len1 = tree[L].len1 + tree[R].len1;
}
void build(int i,int l,int r){
	tree[i] = {l,r,0,0,0,0};
	if(l >= r) return;
	int mid = l + r >> 1;
	build(L,l,mid);
	build(R,mid+1,r);
}
void change(int i,int l,int r,int v){
	if(tree[i].l >= l && tree[i].r <= r){
		tree[i].cnt += v;
		getlen(i);
		return;
	}
	int mid = tree[i].l + tree[i].r >> 1;
	if(r <= mid) change(L,l,r,v);
	else if(l > mid) change(R,l,r,v);
	else{
		change(L,l,mid,v);
		change(R,mid+1,r,v);
	}
	getlen(i);
}
int main(){
	int n,t;
	scanf("%d",&t);
	fir(i,1,t){
		scanf("%d",&n);
		int cnt = 0;
		all.clear();
		all.pb(-1);
		fir(i,1,n){
			double x1,x2,y1,y2;
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			all.pb(x1);all.pb(x2);all.pb(y1);all.pb(y2);
			p[++cnt] = {x1,y1,y2,1};
			p[++cnt] = {x2,y1,y2,-1};
		}
		sort(p+1,p+1+cnt);
		sort(ALL(all));
		all.erase(unique(ALL(all)),all.end());
		build(1,1,(int)all.size()-1);
		double ans = 0;
		p[0].x = p[1].x;
		fir(i,1,cnt){
			int y1 = getpos(p[i].y1),y2 = getpos(p[i].y2);
			ans += tree[1].len2*(p[i].x-p[i-1].x);
			change(1,y1,y2-1,p[i].k);
		}
		printf("%.2lf\n",ans);
	}
	
	return 0;
}	

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/106199390