2646 线段树练习题三

题目

给定一条长度为m的线段,有n个操作,每个操作有3个数字x,y,z表示把区间[x,y]染成颜色z,询问染完色之后,这条长度为m的线段一共有几种颜色。规定:线段的颜色可以相同。连续的相同颜色被视作一段。问x轴被分成多少段。
N <= 10000
M <= 1000000

题解

线段树,和练习题二的插入算法一样。

统计时,若一个区间由单一颜色组成,则把该区间的边界颜色(即最左和最右)作为变量形参带回上一区间,并将返回值设为1
若由多种颜色组成,则递归它的左右儿子,把左右儿子的返回值相加作为自己的返回值,并比较两个字区间的相交部分(即左儿子的最右和右儿子的最左)颜色,若相同且不为-1,则返回值减1

最后输出统计的返回值

时间复杂度O(n log m)

代码

type
  bec=record
        b,e:longint;
        c:longint;
      end;
var
  n,m,i,x,y,z,j,k,ans:longint;
  t:array[1..1000000]of bec;

procedure setup(p:longint);
var
  m:longint;
begin
  if t[p].e-t[p].b>1 then
    begin
      m:=(t[p].e+t[p].b) div 2;
      t[p*2].b:=t[p].b;
      t[p*2].e:=m;
      t[p*2+1].b:=m;
      t[p*2+1].e:=t[p].e;
      setup(p*2);
      setup(p*2+1);
    end;
end;

procedure insert(p,x,y,z:longint);
var
  m:longint;
begin
  if t[p].c<>z then
    begin
      if (x=t[p].b)and(y=t[p].e) then t[p].c:=z else
        begin
          m:=(t[p].b+t[p].e)div 2;
          if t[p].c>=0 then
            begin
              t[p*2].c:=t[p].c;
              t[p*2+1].c:=t[p].c;
              t[p].c:=-1;
            end;
          if y<=m then insert(p*2,x,y,z) else
          if x>=m then insert(p*2+1,x,y,z) else
            begin
              insert(p*2,x,m,z);
              insert(p*2+1,m,y,z);
            end;
        end;
    end;
end;

function count(p:longint;var l,r:longint):longint;
var
  k,d,e:longint;
begin
  if t[p].c>=0 then
    begin
      l:=t[p].c;r:=t[p].c;
      count:=1;
      exit;
    end;
  if t[p].e-t[p].b>1 then
    begin
      k:=count(p*2,l,d)+count(p*2+1,e,r);
      if (d=e)and(l>=0) then dec(k);
      count:=k;
    end;
end;

begin
  readln(n,m);
  t[1].b:=1;t[1].e:=m;
  setup(1);
  for i:=1 to n do
    begin
      readln(x,y,z);
      insert(1,x,y,z);
    end;
  writeln(count(1,x,y));
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值