Shaping Regions(USACO 3.1.4)解题报告

题解配图(转载):

首先声明,本题是一个二维染色的线段树题目,但是又不能用二维的方法做(40000*40000的空间,一定MLE),所以本题应该采用离散化处理+线段树染色的方法,除了最后一个点需要1.12s外,其余全部点全都无压力AC
把x轴上的点离散化,拿y轴做一棵线段树,然后染色即可。
由此,我们又不得不说说线段树染色这个问题。
线段树染色问题也是线段树问题中一类比较经典的问题了,而解决这类问题,主要用到的就是lazy-tag思想。
首先,对于插入线段树:
依照要求,只有当插入线段能完全覆盖当前区间的时候,我们才能进行染色,同时使插入到此结束,(因为已经能完整的表示一个状态),当不能完全覆盖的时候,如果当前区间已经被某一颜色覆盖过,我们可以完全擦除掉这一区间的颜色,让它的子树来保持这一性质,即让子树拥有它的颜色,然后擦除掉它的颜色,这样我们既做到了保持性质,又能很好的覆盖。
CODE如下:

procedure insert(t,l,r,col:longint);
begin
	if (l=tree[t].l) and (r=tree[t].r) then 
		begin
			tree[t].col:=col;
			exit;
		end;
	if tree[t].l=tree[t].r-1 then 
		begin
			tree[t].col:=col;
			exit;
		end;
	if tree[t].col>0 then
		begin
			tree[tree[t].lc].col:=tree[t].col;
			tree[tree[t].rc].col:=tree[t].col;
			tree[t].col:=-1;
		end;
	if r<=tree[tree[t].lc].r then insert(tree[t].lc,l,r,col)
	else if l>=tree[tree[t].rc].l then insert(tree[t].rc,l,r,col)
	else
		begin
			insert(tree[t].lc,l,tree[tree[t].lc].r,col);
			insert(tree[t].rc,tree[tree[t].rc].l,r,col);
		end;
end;

对于得到当前线段树的颜色种类:
这就比较简单了,如果当前区间的颜色不为0,代表它被完全覆盖过,这样就有了一种颜色,然后通过左右子树和递归的调用实现这一问题。在此不再贴出CODE。

program rect1;

type atp=record
		dx,dy,ux,uy:longint;//dx,dy,ux,uy分别代表左下角和右上角的点,这样就构成了一个矩形
	end;

type tre=record
		l,r,lc,rc,col:longint;//col代表当前区间的颜色
	end;

var
	i,j,a,b,n,root,tot:longint;
	ops,color,ans:array [0..10000] of longint;
	tree:array [0..10000*4] of tre;
	mem:array [0..1000] of atp;
	flag:array [0..10000] of boolean;

procedure build(var t:longint;l,r:longint);
begin
	inc(tot);
	t:=tot;
	tree[t].l:=l;
	tree[t].r:=r;
	tree[t].col:=1;
	if l=r-1 then exit;//为什么分到[l,l+1]这个区间就结束了线段树的建立呢,这点在后面的程序中会有说到
	build(tree[t].lc,l,(l+r) shr 1); 
	build(tree[t].rc,(l+r) shr 1,r);
	//同理,后面会有说到
end;
	
procedure insert(t,l,r,col:longint);//插入带染色的线段树的过程
begin
	if (l=tree[t].l) and (r=tree[t].r) then 
		begin
			tree[t].col:=col;
			exit;
		end;
	if tree[t].l=tree[t].r-1 then 
		begin
			tree[t].col:=col;
			exit;
		end;
	if tree[t].col>0 then
		begin
			tree[tree[t].lc].col:=tree[t].col;
			tree[tree[t].rc].col:=tree[t].col;
			tree[t].col:=-1;
		end;
	if r<=tree[tree[t].lc].r then insert(tree[t].lc,l,r,col)
	else if l>=tree[tree[t].rc].l then insert(tree[t].rc,l,r,col)
	else
		begin
			insert(tree[t].lc,l,tree[tree[t].lc].r,col);
			insert(tree[t].rc,tree[tree[t].rc].l,r,col);
		end;
end;
	
procedure get(t:longint);
begin
	if tree[t].col>0 then 
		begin
			inc(ans[tree[t].col],(ops[i+1]-ops[i])*(tree[t].r-tree[t].l));//通过离散化,实现了对染色面积的计算(两条线段夹的线段即为矩形的长,宽即为线段树的长度),看到了吧(ops[i+1]-ops[i])*(tree[t].r-tree[t].l),这就是之前为什么不能那么建树的原因了,左右端点相同时,结果为0毫无意义
			exit;
		end;
	get(tree[t].lc);
	get(tree[t].rc);
end;
	
begin
	assign(input,'rect1.in'); reset(input);
	assign(output,'rect1.out'); rewrite(output);
	
	root:=0;
	tot:=0;
	fillchar(ans,sizeof(ans),0);
	fillchar(ops,sizeof(ops),0);
	fillchar(mem,sizeof(mem),0);
	fillchar(flag,sizeof(flag),false);
	readln(a,b,n);
	build(root,0,a);
	for i:=1 to n do
		begin
			readln(mem[i].dx,mem[i].dy,mem[i].ux,mem[i].uy,color[i]);
			flag[mem[i].dx]:=true;
			flag[mem[i].ux]:=true;
		end;
	tot:=0;
	for i:=0 to 10000 do 
		begin
			if flag[i] then
				begin
					inc(tot);
					ops[tot]:=i;
				end;
		end;
	//离散化的实现过程,在此不再赘述
	for i:=1 to tot-1 do
		begin
			insert(root,0,a,1);
			for j:=1 to n do if (ops[i]>=mem[j].dx) and (ops[i]<mem[j].ux) then insert(root,mem[j].dy,mem[j].uy,color[j]);//注意:if (ops[i]>=mem[j].dx) and (ops[i]<mem[j].ux) 很好的解决了避免插入一条线的情况
			get(root);
		end;
	inc(ans[1],ops[1]*a+(b-ops[tot])*a);//1的面积还要加上靠近y轴及最远离y轴且平行y轴的那一段
	for i:=1 to 2500 do if ans[i]>0 then writeln(i,' ',ans[i]);
	
	close(input); close(output);
end.

终于结束了,这破鸟题。。#%¥#!%¥……!#@¥

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值