题解配图(转载):
首先声明,本题是一个二维染色的线段树题目,但是又不能用二维的方法做(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.终于结束了,这破鸟题。。#%¥#!%¥……!#@¥
解题报告&spm=1001.2101.3001.5002&articleId=6586910&d=1&t=3&u=37024b8160554d76a5ae5783618b55b7)
1494

被折叠的 条评论
为什么被折叠?



