ZJU P1610 count the colors

题目大意:
在一条长度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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值