桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如右图所示。现在从桌子的前方射来一束平行光,把盒子的影子投射到了墙上。问影子的总宽度是多少?
分析:使用一个下标范围为[min,max-1]的一维数组,其中数组的第i个元素表示[i,i+1]的区间,将[a,b]内所有对应的数组元素均设为1。最后统计数组中1的个数即可。当下标范围很大时,速度会很慢。这样就需要用线段树(二叉树)来写了。
如果根节点为1—n,那么两个儿子节点分别为1—mid和mid—n(注意:其中1、mid、n是点)。
每个节点都可以记录一些信息。在该题中,加一个cover,记录i—j完全覆盖与否,就可以快速求解,再加上离散化,可以大大节约内存。
const
maxn=2000;
type
tnode=record
b,e:integer; {节点的范围}
cover:integer; {完全覆盖为1,不完全覆盖为0}
end;
var
tree:array[1..maxn] of tnode;
n,total:integer;
procedure insert(p,a,b:integer);
var
m:integer;
begin
iftree[p].cover=0
thenbegin
m:=(tree[p].b+tree[p].e) div 2; //求mid
if (tree[p].b=a) and(tree[p].e=b) //如果插入的范围刚好为tree[b—e],那//么直接赋值为完全覆盖
then tree[p].cover:=1
else begin
if b<=m
then insert(p*2,a,b) //如果插入的范围只在左节点,那么直接//枚举左儿子
else if a>=m
theninsert(p*2+1,a,b) //只有右儿子
else begin
insert(p*2,a,m); //既有左儿子,又有右儿子
insert(p*2+1,m,b);
end;
end;
end;
end;
function count(p:integer):integer;//递归求和
begin
iftree[p].cover=1
thencount:=tree[p].e-tree[p].b
else iftree[p].e-tree[p].b=1
then count:=0
else count:=count(p*2)+count(p*2+1);
end;
procedure create(p:integer);//建树,可以用离散化优化
var
m:integer;
begin
iftree[p].e-tree[p].b>1 then
begin
m:=(tree[p].e+tree[p].b) div 2;
tree[p*2].b:=tree[p].b;
tree[p*2].e:=m;
tree[p*2+1].b:=m;
tree[p*2+1].e:=tree[p].e;
create(p*2);
create(p*2+1);
end;
end;
procedure main;
var
i:integer;
a,b,l:integer;
begin
readln(l);
tree[1].b:=1;tree[1].e:=l;
create(1);
readln(n);
for i:=1to n do
begin
read(a,b);
insert(1,a,b);
end;
total:=count(1);
end;
begin
main;
writeln(total);
end.