像我这种蒟蒻这道题从在线算法思考基本毫无思路
但是发现题目中只涉及到询问而不涉及到修改,这类题目一般都是离线算法大概
考虑到这题为什么不能直接区间求值,因为区间中同色点会被重复计算(废话)
下面我们就要通过离线算法来排除区间内同色点干扰
首先想到对询问区间以左端点排序,
考虑到区间内的同色点我们只要算最左边的就行了
先将每种颜色第一次出现的位置标记为1
然后从左往右扫描每一个位置,算出以这个位置为左端点的区间答案(区间和)
然后再将这个位置颜色的下一个同色位置标记
这样我们就保证了每次区间询问,同色点只算了一遍
因为一个区间内要么不存在同色点,
要么同色点只出现了一次(被标记了一次),下一个同色点一定还没有标记,而上一个同色点一定在区间外左侧
语言表述不太好,具体还是看程序吧……
1 var a,c,next:array[0..60010] of longint; 2 x,y,ans,p:array[0..200010] of longint; 3 last:array[0..1000000] of longint; 4 max,i,n,m,j:longint; 5 function lowbit(x:longint):longint; 6 begin 7 exit(x and(-x)); 8 end; 9 10 function sum(x:longint):longint; 11 begin 12 sum:=0; 13 while x<>0 do 14 begin 15 sum:=sum+c[x]; 16 x:=x-lowbit(x); 17 end; 18 end; 19 20 procedure add(x:longint); 21 begin 22 while x<=n do 23 begin 24 inc(c[x]); 25 x:=x+lowbit(x); 26 end; 27 end; 28 29 procedure swap(var a,b:longint); 30 var c:longint; 31 begin 32 c:=a; 33 a:=b; 34 b:=c; 35 end; 36 37 procedure sort(l,r: longint); 38 var i,j,z: longint; 39 begin 40 i:=l; 41 j:=r; 42 z:=x[(l+r) div 2]; 43 repeat 44 while x[i]<z do inc(i); 45 while z<x[j] do dec(j); 46 if not(i>j) then 47 begin 48 swap(x[i],x[j]); 49 swap(y[i],y[j]); 50 swap(p[i],p[j]); 51 inc(i); 52 dec(j); 53 end; 54 until i>j; 55 if l<j then sort(l,j); 56 if i<r then sort(i,r); 57 end; 58 59 begin 60 readln(n); 61 for i:=1 to n do 62 begin 63 read(a[i]); 64 if max<a[i] then max:=a[i]; 65 end; 66 readln(m); 67 for i:=1 to m do 68 begin 69 readln(x[i],y[i]); 70 p[i]:=i; 71 end; 72 sort(1,m); 73 fillchar(last,sizeof(last),0); 74 for i:=n downto 1 do //计算每个位置下一个同色点的位置 75 begin 76 next[i]:=last[a[i]]; 77 last[a[i]]:=i; 78 end; 79 for i:=1 to max do //先映射每种颜色第一次出现的位置 80 if last[i]<>0 then add(last[i]); 81 82 j:=1; 83 for i:=1 to n do 84 begin 85 while x[j]=i do 86 begin 87 ans[p[j]]:=sum(y[j])-sum(x[j]-1); 88 inc(j); 89 end; 90 if next[i]<>0 then add(next[i]); 91 end; 92 for i:=1 to m do 93 writeln(ans[i]); 94 end.