像我这种蒟蒻这道题从在线算法思考基本毫无思路

但是发现题目中只涉及到询问而不涉及到修改,这类题目一般都是离线算法大概

考虑到这题为什么不能直接区间求值,因为区间中同色点会被重复计算(废话)

下面我们就要通过离线算法来排除区间内同色点干扰

首先想到对询问区间以左端点排序,

考虑到区间内的同色点我们只要算最左边的就行了

先将每种颜色第一次出现的位置标记为1

然后从左往右扫描每一个位置,算出以这个位置为左端点的区间答案(区间和)

然后再将这个位置颜色的下一个同色位置标记

这样我们就保证了每次区间询问,同色点只算了一遍

因为一个区间内要么不存在同色点,

要么同色点只出现了一次(被标记了一次),下一个同色点一定还没有标记,而上一个同色点一定在区间外左侧

语言表述不太好,具体还是看程序吧……

 var a,c,next:array[..] of longint;
    x,y,ans,p:array[..] of longint;
    last:array[..] of longint;
    max,i,n,m,j:longint;
function lowbit(x:longint):longint;
  begin
    exit(x and(-x));
  end; function sum(x:longint):longint;
  begin
    sum:=;
    while x<> do
    begin
      sum:=sum+c[x];
      x:=x-lowbit(x);
    end;
  end; procedure add(x:longint);
  begin
    while x<=n do
    begin
      inc(c[x]);
      x:=x+lowbit(x);
    end;
  end; procedure swap(var a,b:longint);
  var c:longint;
  begin
    c:=a;
    a:=b;
    b:=c;
  end; procedure sort(l,r: longint);
  var i,j,z: longint;
  begin
    i:=l;
    j:=r;
    z:=x[(l+r) div ];
    repeat
      while x[i]<z do inc(i);
      while z<x[j] do dec(j);
      if not(i>j) then
      begin
        swap(x[i],x[j]);
        swap(y[i],y[j]);
        swap(p[i],p[j]);
        inc(i);
        dec(j);
      end;
    until i>j;
    if l<j then sort(l,j);
    if i<r then sort(i,r);
  end; begin
  readln(n);
  for i:= to n do
  begin
    read(a[i]);
    if max<a[i] then max:=a[i];
  end;
  readln(m);
  for i:= to m do
  begin
    readln(x[i],y[i]);
    p[i]:=i;
  end;
  sort(,m);
  fillchar(last,sizeof(last),);
  for i:=n downto do  //计算每个位置下一个同色点的位置
  begin
    next[i]:=last[a[i]];
    last[a[i]]:=i;
  end;
  for i:= to max do   //先映射每种颜色第一次出现的位置
    if last[i]<> then add(last[i]);   j:=;
  for i:= to n do
  begin
    while x[j]=i do
    begin
      ans[p[j]]:=sum(y[j])-sum(x[j]-);
      inc(j);
    end;
    if next[i]<> then add(next[i]);
  end;
  for i:= to m do
    writeln(ans[i]);
end.
05-08 15:09