题目大意:
在一条长度0~8000的线段上染色,每次把区间[l,r]染成某种颜色。显然,后面染上去的颜色会覆盖掉之前的颜色,求染色完以后,每种颜色在这条线段上有多少个间断的区间。
颜色不重复
0<=l<=r<=8000 1<=n,颜色类型 <=8000
题解:
线段树:
1.就是一个普通的线段树改一下,建树要用0~8000开始建。
tree[p]=-2表示它所对应的区间[l,r]未被染色过。
tree[p]=-1代表它所对应的区间[l,r]的lazy操作已经做了。
除了上面以外,tree[p]都表示区间[l,r]的颜色。
2.用一个递归求解。
注意:
题目是一个线段而不是一个个点。
例:假设数据输入的区间大小都在0~4之间,
初始
-2 X(-2) -2 X(-2) -2 X(-2) -2 X(-2) -2
(X()表示间隔颜色,-2表示无颜色)
覆盖0~4 颜色为0,即
0 X(0) 0 X(0) 0 X(0) 0 X(0) 0
覆盖0~2 颜色为1,即
1 X(1) 1 X(1) 1 X(0) 0 X(0) 0
覆盖3~4 颜色为2,即
1 X(1) 1 X(1) 1 X(0) 2 X(2) 2
这时候
0颜色的有1个,1颜色的有1个,2颜色的有一个,而如果当成点来算的话,那么就忽略了间隔,这时候0颜色就不会被找到。
var
tree:array [0..30000] of longint;
sum:array [0..8001] of longint;
i,n,a,b,c:longint;
procedure insert(p,l,r,a,b:longint);
var
mid:longint;
begin
mid:=(l+r) div 2;
if (a=l) and (b=r)
then tree[p]:=c
else begin
if tree[p]<>-1
then begin
tree[p * 2]:=tree[p];
tree[p*2+1]:=tree[p];
tree[p]:=-1;
end;
if b<=mid then insert(p*2,l,mid,a,b)
else if a>=mid then insert(p*2+1,mid,r,a,b)
else begin
insert(p * 2,l,mid,a,mid);
insert(p*2+1,mid,r,mid,b);
end;
end;
end;
procedure count(p,l,r:longint);
var
mid:longint;
begin
mid:=(l+r) div 2;
if tree[p]=-2
then begin
c:=-2;
exit;
end
else if (tree[p]<>c) and (tree[p]<>-1)
then begin
c:=tree[p];
inc(sum[c]);
end
else if (r-l=1) and (c=tree[p])
then exit
else if tree[p]=-1
then begin
count(p * 2,l,mid);
count(p*2+1,mid,r);
end;
end;
procedure print;
begin
for i:=0 to 8000 do
if sum[i]<>0 then writeln(i,' ',sum[i]);
writeln;
end;
begin
while not eof do
begin
fillchar(sum,sizeof(sum),0);
for i:=0 to 30000 do tree[i]:=-2;
readln(n);
for i:=1 to n do
begin
readln(a,b,c);
insert(1,0,8000,a,b);
end;
c:=-3;
count(1,0,8000);
print;
end;
end.