bzoj 1878 树状数组+离线

19 篇文章 0 订阅
4 篇文章 0 订阅

题意:m组询问,求[l,r]中包含了多少种不同的权值

离线+树状数组,还是原来的配方,还是熟悉的呆马...

把询问按l从小到大排序,

i指针从1到n扫,保证每种权值在[i,r]中第一次出现的位置在树状数组中赋为1,其余位置为0

当i与当前询问的l重合时,当前询问的答案为[l,r]的区间和

type
        rec=record
            l,r,num:longint;
end;

var
        n,m,tot,ll      :longint;
        i,j             :longint;
        ans             :array[0..200010] of longint;
        a               :array[0..200010] of rec;
        first,last      :array[0..1000010] of longint;
        t               :array[0..100010] of longint;
        c,next          :array[0..50010] of longint;
function lowbit(x:longint):longint;
begin
   exit(x and (-x));
end;

procedure sort1(ll,rr:longint);
var
        i,j:longint;
        x:longint;
        y:rec;
begin
   i:=ll;j:=rr;
   x:=a[(ll+rr) div 2].l;
   while (i<=j) do
   begin
      while (a[i].l<x) do inc(i);
      while (a[j].l>x) do dec(j);
      if (i<=j) then
      begin
         y:=a[i];a[i]:=a[j];a[j]:=y;
         inc(i);dec(j);
      end;
   end;
   if (i<rr) then sort1(i,rr);
   if (j>ll) then sort1(ll,j);
end;

procedure add(x:longint);
begin
   while (x<=n) do
   begin
      inc(t[x]);
      inc(x,lowbit(x));
   end;
end;

function find(x:longint):longint;
var
        ans:longint;
begin
   ans:=0;
   while (x>0) do
   begin
      inc(ans,t[x]);
      dec(x,lowbit(x));
   end;
   exit(ans);
end;

begin
   read(n);
   for i:=1 to n do
   begin
      read(c[i]);
      if (c[i]>tot) then tot:=c[i];
   end;
   //
   read(m);
   for i:=1 to m do read(a[i].l,a[i].r);
   for i:=1 to m do a[i].num:=i;
   sort1(1,m);
   for i:=1 to n do
   begin
      if (last[c[i]]=0) then
      begin
         last[c[i]]:=i;
         first[c[i]]:=i;
      end else
      begin
         next[last[c[i]]]:=i;
         last[c[i]]:=i;
      end;
   end;

   //
   for i:=1 to tot do
     if (first[i]<>0) then add(first[i]);
   //
   ll:=1;
   for i:=1 to m do
   begin
      for j:=ll to a[i].l-1 do
        if next[j]<>0 then add(next[j]);
      ans[a[i].num]:=find(a[i].r)-find(a[i].l-1);
      ll:=a[i].l;
   end;
   //
   for i:=1 to m do writeln(ans[i]);
end.
——by Eirlys

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值