扫描线

这里提供求矩形面积并的扫描线。

你可以根据自己的需要更改基本数据类型 S_B_TS\_B\_T

#define S_B_T long long

上面实现了一个以 long long 为基本数据类型的定义。

所有的函数已经完成,所以你只需要用到两个函数:

insert(x1,y1,x2,y2)\text{insert}(x_1,y_1,x_2,y_2):插入一个矩形,左上角为 (x1,y1)(x_1,y_1),右下角为 (x2,y2)(x_2,y_2)

ask_area()\text{ask\_area}():求此时的矩形面积并。

#define pl p<<1
#define pr p<<1|1
#define S_B_T long long
struct Scanning_Beam{
	int tot;
	vector<S_B_T>y_set;
	struct Tree{
		int l,r;
		S_B_T len,cnt;
	}a[8*N];
	struct Line{
		S_B_T x,y1,y2,k;
		bool operator<(const Line &a)const{ 
	        return x<a.x;
	    }
	}b[2*N],e;
	Scanning_Beam(){
		tot=0;
	}
	int find(S_B_T y){
		return lower_bound(y_set.begin(),y_set.end(),y)-y_set.begin();
	}
	void pushup(int p){
		if(a[p].cnt)
			a[p].len=y_set[a[p].r+1]-y_set[a[p].l];
		else if(a[p].l^a[p].r)
			a[p].len=a[pl].len+a[pr].len;
		else
			a[p].len=0;
	}
	void build(int p,int l,int r){
		a[p].l=l;a[p].r=r;
		a[p].len=a[p].cnt=0;
		if(l==r)
			return;
		int mid=l+r>>1;
		build(pl,l,mid);
		build(pr,mid+1,r);
		pushup(p);
	}
	void modify(int p,int l,int r,S_B_T x){
		if(l<=a[p].l&&a[p].r<=r){
			a[p].cnt+=x;
			pushup(p);
			return;
		}
		int mid=a[p].l+a[p].r>>1;
		if(l<=mid)
			modify(pl,l,r,x);
		if(r>mid)
			modify(pr,l,r,x);
		pushup(p);
	}
	void add(S_B_T x,S_B_T y1,S_B_T y2,S_B_T k){
		e.x=x;e.y1=y1;
		e.y2=y2;e.k=k;
		b[tot++]=e;
	}
	void insert(S_B_T x1,S_B_T y1,S_B_T x2,S_B_T y2){
		add(x1,y1,y2,1);
		add(x2,y1,y2,-1);
		y_set.push_back(y1);
		y_set.push_back(y2);
	}
	S_B_T ask_area(){
		S_B_T ans=0;
		sort(y_set.begin(),y_set.end());
		y_set.erase(unique(y_set.begin(),y_set.end()),y_set.end());
		build(1,0,y_set.size()-2);
		sort(b,b+tot);
		for(int i=0;i<tot;i++){
			if(i)
				ans+=a[1].len*(b[i].x-b[i-1].x);
			modify(1,find(b[i].y1),find(b[i].y2)-1,b[i].k);
		}
		return ans;
	}
}tree;

空间复杂度 O(10N)O(10N)insert\text{insert} 操作时间复杂度为 O(1)O(1)ask_area\text{ask\_area} 操作时间复杂度为 O(nlogn)O(n\log n)

posted @ 2021-08-31 13:32  luckydrawbox  阅读(7)  评论(0)    收藏  举报  来源