矩形的面积并

硬上了面积并,觉得有点爽。。

扫描线+线段树嘛。。

重点:扫描线法:假想有一条扫描线,从左往右(从右往左),或者从下往上(从上往下)扫描过整个多边形(或者说畸形。。多个矩形叠加后的那个图形)

   扫描之前还需要做一个工作,就是保存好所有矩形的上下边,并且按照它们所处的高度进行排序,另外如果是上边我们给他一个值-1,下边给他一个值1,我们用一个结构体来保存所有的上下边 

struct segment
{
double l,r,h;   //l,r表示这条上下边的左右坐标,h是这条边所处的高度
int f;   //所赋的值,1或-1
}

接着扫描线从下往上扫描,每遇到一条上下边就停下来,将这条线段投影到总区间上(总区间就是整个多边形横跨的长度),这个投影对应的其实是个插入和删除线段操作。还记得给他们赋的值1或-1吗,下边是1,扫描到下边的话相当于往总区间插入一条线段,上边-1,扫描到上边相当于在总区间删除一条线段(如果说插入删除比较抽象,那么就直白说,扫描到下边,投影到总区间,对应的那一段的值都要增1,扫描到上边对应的那一段的值都要减1,如果总区间某一段的值为0,说明其实没有线段覆盖到它,为正数则有,那会不会为负数呢?是不可能的,可以自己思考一下)。

每扫描到一条上下边后并投影到总区间后,就判断总区间现在被覆盖的总长度,然后用下一条边的高度减去当前这条边的高度,乘上总区间被覆盖的长度,就能得到一块面积,并依此做下去,就能得到最后的面积

(这个过程其实一点都不难,只是看文字较难体会,建议纸上画图,一画即可明白,下面献上一图希望有帮助)

我就是看这个看懂的。。

所以它是怎么实现的我就不说了。。

那么我要说的是线段树

或许要问:有没有必要打lazy-tag呢?。。

其实没有必要。。

看我的代码,就会明白没有lazy-tag也是可以的。。

因为我们要求的只是最上层的,下面的没有用。。

也许下层的sum是错误的,但只要sum[1]正确即可。。

Code:

const shuru='matrix.in';
	  shuchu='matrix.out';
	  maxm=8500000;
	  maxn=200000;
type treenode=record
		left,right:longint;
               sum,cover:int64;
			  end;
var	tree:Array[0..maxm+1] of treenode;
	y,x1,x2,k:array[0..maxn] of int64;
	t,num,a,b,c,d,maxlen,i,j,n:longint;
	ans:int64;
procedure build(x,l,r:longint);inline;
var mid:longint;
begin
	tree[x].left:=l; tree[x].right:=r;
	mid:=(l+r) shr 1;
	if mid<>l then begin
						build(x shl 1,l,mid);
						build(x shl 1+1,mid,r);
				   end;
end;
procedure qsort(left,right:longint);inline;
var i,j,mid:longint;
begin
	i:=left; j:=right; mid:=y[(i+j) div 2];
	repeat
		while y[i]<mid do inc(i);
		while y[j]>mid do dec(j);
		if i<=j then begin
						t:=y[i]; y[i]:=y[j]; y[j]:=t;
						t:=x1[i]; x1[i]:=x1[j]; x1[j]:=t;
						t:=x2[i]; x2[i]:=x2[j]; x2[j]:=t;
						t:=k[i]; k[i]:=k[j]; k[j]:=t;
						inc(i); dec(j);
					 end;
	until i>j;
	if j>left  then qsort(left,j);
	if i<right then qsort(i,right);
end;
function max(a,b:longint):longint;inline;
begin
	if a>b then exit(a);
	exit(b);
end;
procedure init;
begin
	readln(n);
	for i:=1 to n do
	begin
		readln(a,b,c,d);
		inc(num);
		y[num]:=b;
		x1[num]:=a;
		x2[num]:=a+c;
		k[num]:=1;
		inc(num);
		y[num]:=b+d;
		x1[num]:=a;
		x2[num]:=a+c;
		k[num]:=-1;
		maxlen:=max(maxlen,a+c);
	end;
end;
procedure ins(x,a,b,data:longint);inline;
var mid:longint;
begin
	if (a<=tree[x].left) and (b>=tree[x].right) then 
												  inc(tree[x].cover,data)
												else 
												begin
													mid:=(tree[x].left+tree[x].right) shr 1;
													if a<mid then ins(x shl 1,a,b,data);
													if b>mid then ins(x shl 1+1,a,b,data);
												end;
	if tree[x].cover>0 then tree[x].sum:=tree[x].right-tree[x].left
					   else tree[x].sum:=tree[x shl 1].sum+tree[x shl 1+1].sum;
end;
procedure main;
begin
	init;
	qsort(1,2*n);
	build(1,0,maxlen);
	ins(1,x1[1],x2[1],k[1]);
	for i:=2 to 2*n do
	begin
		ans:=ans+(y[i]-y[i-1])*tree[1].sum;
		ins(1,x1[i],x2[i],k[i]);
	end;
	writeln(ans);
end;
begin
	main;
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值