明显的数据结构题
这道题的特殊性在于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.
View Code

 

posted on 2014-10-25 22:40  acphile  阅读(120)  评论(0编辑  收藏  举报