[BZOJ2453]维护队列|分块
Description
你小时候玩过弹珠吗?小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。
思路很简单,在[l,r]中出现过的颜色数量
我们设b[i]为第i位的数其之前出现的时候的下标
只要统计在[l,r]间,b[i]<l的数量即可
只要在每次修改的时候维护好b,再每次排序,询问的时候二分查找即可。
如何维护b呢?
对于每一个修改,它最多影响两个数的b,一个是它自身,一个是它后面遇到的第一个与它相等的数
我们只要重新对两个块排序
但是处理处b,刚开始我想要在每个块中再维护一个以颜色为第一关键字,下标为第二关键字的序列
对于每个块二分找到修改的点前一次出现的位置 但是感觉十分麻烦
看了下数据,修改的次数不会超过1000,n<=10000,每次重新算一遍b数组也是可以的
但是第一次提交TLE了,发现习惯性的fillchar实际上时间并不那么快
统计b的last数组实际上O(n)赋值比fillchar要快得多(因为last的范围的[0..10^6]啊/w\)
1 program bzoj2453; 2 const maxn=10010;maxm=1000010; 3 var n,m,i,block,x,y,q:longint; 4 ch:char; 5 pos,a,b,pre:array[-1..maxn]of longint; 6 last:array[-1..maxm]of longint; 7 8 function min(a,b:longint):longint; 9 begin 10 if a<b then exit(a) else exit(b); 11 end; 12 13 procedure qsort(L,R:longint); 14 var i,j,mid:longint; 15 begin 16 i:=L;j:=R;mid:=pre[random(R-L+1)+L]; 17 repeat 18 while (i<R)and(pre[i]<mid) do inc(i); 19 while (L<j)and(pre[j]>mid) do dec(j); 20 if i<=j then 21 begin 22 pre[0]:=pre[i];pre[i]:=pre[j];pre[j]:=pre[0]; 23 inc(i);dec(j); 24 end; 25 until i>j; 26 if i<R then qsort(i,R); 27 if L<j then qsort(L,j); 28 end; 29 30 procedure new(x:longint); 31 var l,r,i:longint; 32 begin 33 l:=(x-1)*block+1;r:=min(x*block,n); 34 for i:=l to r do pre[i]:=b[i]; 35 qsort(l,r); 36 end; 37 38 procedure change(x,y:longint); 39 var i:longint; 40 begin 41 for i:=1 to n do last[a[i]]:=0; 42 a[x]:=y; 43 for i:=1 to n do 44 begin 45 if last[a[i]]<>b[i] then 46 begin 47 48 b[i]:=last[a[i]]; 49 new(pos[i]); 50 end; 51 b[i]:=last[a[i]]; 52 last[a[i]]:=i; 53 end; 54 end; 55 56 function find(x,y:longint):longint; 57 var L,R,mid:longint; 58 begin 59 find:=(x-1)*block; 60 L:=find+1;R:=min(x*block,n); 61 while L<=R do 62 begin 63 mid:=(L+R) >> 1; 64 if pre[mid]<=y then 65 begin 66 find:=mid;L:=mid+1; 67 end else R:=mid-1; 68 end; 69 dec(find,(x-1)*block); 70 end; 71 72 procedure build; 73 var i:longint; 74 begin 75 for i:=1 to n do last[a[i]]:=0; 76 for i:=1 to n do 77 begin 78 b[i]:=last[a[i]]; 79 last[a[i]]:=i; 80 end; 81 for i:=1 to m do new(i); 82 end; 83 84 function query(x,y:longint):longint; 85 var i,tot:longint; 86 begin 87 tot:=0; 88 if pos[x]=pos[y] then 89 begin 90 for i:=x to y do if b[i]<=x-1 then inc(tot); 91 end else 92 begin 93 for i:=x to pos[x]*block do if b[i]<=x-1 then inc(tot); 94 for i:=(pos[y]-1)*block+1 to y do if b[i]<=x-1 then inc(tot); 95 for i:=pos[x]+1 to pos[y]-1 do inc(tot,find(i,x-1)); 96 end; 97 exit(tot); 98 end; 99 100 begin 101 readln(n,q); 102 block:=trunc(sqrt(n)); 103 for i:=1 to n do 104 begin 105 read(a[i]); 106 pos[i]:=(i-1) div block+1; 107 end; 108 readln; 109 if n mod block=0 then m:=n div block else m:=n div block+1; 110 build; 111 for i:=1 to q do 112 begin 113 read(ch); 114 if ch='Q' then 115 begin 116 readln(x,y); 117 writeln(query(x,y)); 118 end else 119 begin 120 readln(x,y); 121 change(x,y); 122 end; 123 end; 124 end.