明显的数据结构题
这道题的特殊性在于n只有10000,修改的操作只有1000
那么就是说即便是O(n)的修改也没有太大的问题,只要常数写小一点即可
考虑到以前对同色点的处理
pre[i]表示与这个位置同色的前一个位置
对于一段区间l,r,如果区间中位置i,满足pre[i]<l则这个位置上的颜色是一种,被算一次
直接扫描显然O(n),但假如这段位置pre有序,我们就可以用二分
但是如果整体排序我们就不好确定区间的位置
因此我们考虑分块,每块内pre排序,当查询区间[l,r]时
先暴力统计l,r所在块内,在用二分统计在l,r所在块之间的块每块中符合条件的个数
这样的复杂度还是可以接受了
然后考虑修改,首先修改只会对原来颜色和修改成颜色的位置产生影响
我们只要找到原来颜色的下一个同色点位置并修改所在块,
并且找到现在颜色的下一个同色点位置并修改所在块
当然这个位置的所在块也是要修改的
1 var p,pre,b,a:array[0..10010] of longint; 2 v:array[0..10010] of boolean; 3 last:array[0..1000010] of longint; 4 t,n,m,size,i,x,y:longint; 5 ch:char; 6 7 procedure sort(l,r: longint); 8 var i,j,x,y: longint; 9 begin 10 i:=l; 11 j:=r; 12 x:=b[(l+r) div 2]; 13 repeat 14 while b[i]<x do inc(i); 15 while x<b[j] do dec(j); 16 if not(i>j) then 17 begin 18 y:=b[i]; 19 b[i]:=b[j]; 20 b[j]:=y; 21 inc(i); 22 j:=j-1; 23 end; 24 until i>j; 25 if l<j then sort(l,j); 26 if i<r then sort(i,r); 27 end; 28 29 function find(x,y:longint):longint; 30 var l,r,m,f:longint; 31 begin 32 l:=(x-1)*size+1; 33 f:=l; 34 r:=x*size; 35 if r>n then r:=n; 36 while l<=r do 37 begin 38 m:=(l+r) shr 1; 39 if b[m]<y then l:=m+1 40 else r:=m-1; 41 end; 42 exit(l-f); 43 end; 44 45 function ask(l,r:longint):longint; 46 var i:longint; 47 begin 48 ask:=0; 49 if p[l]=p[r] then 50 begin 51 for i:=l to r do //l,r在一个块 52 if pre[i]<l then inc(ask); 53 end 54 else begin //不在一个块 55 for i:=l to p[l]*size do 56 if pre[i]<l then inc(ask); 57 for i:=(p[r]-1)*size+1 to r do 58 if pre[i]<l then inc(ask); 59 for i:=p[l]+1 to p[r]-1 do 60 ask:=ask+find(i,l); 61 end; 62 end; 63 64 procedure build(x:longint); 65 var l,r,i:longint; 66 begin 67 l:=(x-1)*size+1; 68 r:=x*size; 69 if r>n then r:=n; 70 for i:=l to r do 71 b[i]:=pre[i]; //另开一个数组排序方便二分 72 sort(l,r); 73 end; 74 75 procedure change(x,y:longint); 76 var i,j,k:longint; 77 begin 78 if a[x]=y then exit; 79 fillchar(v,sizeof(v),false); 80 i:=last[a[x]]; 81 k:=pre[x]; 82 v[p[x]]:=true; 83 j:=0; 84 while i<>x do 85 begin 86 j:=i; 87 i:=pre[i]; 88 end; 89 if j<>0 then 90 begin 91 pre[j]:=k; 92 v[p[j]]:=true; //原来颜色的下一个同色点的位置所在块要修改 93 end 94 else last[a[x]]:=pre[i]; //如果是原来颜色的最后一个位置 95 96 a[x]:=y; 97 i:=last[y]; 98 if x>i then //如果是现在颜色的最后一个位置 99 begin 100 last[y]:=x; 101 pre[x]:=i 102 end 103 else begin 104 while not((pre[i]<x) and (x<i)) do i:=pre[i]; 105 pre[x]:=pre[i]; //在现在颜色的链上上插入这个位置 106 v[p[i]]:=true; //现在颜色的下一个同色点所在位置要修改 107 pre[i]:=x; 108 end; 109 for i:=1 to t do 110 if v[i] then build(i); 111 end; 112 113 begin 114 readln(n,m); 115 for i:=1 to n do 116 read(a[i]); 117 readln; 118 size:=trunc(sqrt(n)+ln(2*n)/ln(2)); //因为查询的复杂度带了一个logn,所以块的大小这样合适 119 fillchar(last,sizeof(last),255); 120 t:=1; 121 for i:=1 to n do 122 begin 123 p[i]:=t; //每个位置所在块的编号 124 pre[i]:=last[a[i]]; 125 last[a[i]]:=i; 126 if i mod size=0 then inc(t); 127 end; 128 if n mod size=0 then dec(t); 129 for i:=1 to t do 130 build(i); 131 132 for i:=1 to m do 133 begin 134 readln(ch,x,y); 135 if ch='Q' then writeln(ask(x,y)) 136 else change(x,y); 137 end; 138 end.