分块大法好!
首先预处理第i块到第j块的答案,这是可以在O(n*tot)内处理出来的 tot表示块数
然后考虑询问对于[l,r],答案只可能是[l,r]之间所夹整块[i,j]的答案和非整块中的位置上的数
下面我们要做的是快速求出一个数在区间[l,r]出现的次数
当然我一无脑就直接写了主席树,这当然可以复杂度为O(size*logn)
一开始TLE了,好来发现块大小为sqrt(n/log(n))最优,然后跑了20s就过了
后来一想,不对,直接预处理每个数在块1..i出现的次数不就可以了吗
这样求出一个数在区间[l,r]出现的次数只需要O(1)的时间,复杂度仅仅是O(size)
好像是的……这样可以在O(nsqrt(n))的时间内搞出来,这次只跑了7s左右
下面给出算法二
1 const maxn=40010; 2 3 var f:array[0..210,0..maxn] of longint; 4 a1,a2:array[0..1010,0..1010] of longint; 5 be,h,s,a,b,c,rank:array[0..maxn] of longint; 6 ans,x,y,i,p,q,m,t,tot,size,n:longint; 7 8 procedure swap(var a,b:longint); 9 var c:longint; 10 begin 11 c:=a; 12 a:=b; 13 b:=c; 14 end; 15 16 procedure sort(l,r: longint); 17 var i,j,x,y: longint; 18 begin 19 i:=l; 20 j:=r; 21 x:=b[(l+r) div 2]; 22 repeat 23 while b[i]<x do inc(i); 24 while x<b[j] do dec(j); 25 if not(i>j) then 26 begin 27 swap(b[i],b[j]); 28 swap(c[i],c[j]); 29 inc(i); 30 j:=j-1; 31 end; 32 until i>j; 33 if l<j then sort(l,j); 34 if i<r then sort(i,r); 35 end; 36 37 procedure clear(l,r:longint); 38 var i:longint; 39 begin 40 for i:=l to r do 41 s[rank[i]]:=-1; 42 end; 43 44 procedure pre; 45 var i,j,p,q:longint; 46 begin 47 for i:=1 to tot do //预处理在1..i的块中数出现的次数 48 begin 49 p:=i*size; 50 if p>n then p:=n; 51 for j:=(i-1)*size+1 to p do 52 inc(s[rank[j]]); 53 for j:=1 to m do 54 f[i,j]:=s[j]; 55 end; 56 for i:=1 to tot do //预处理i~j块的答案 57 begin 58 p:=0; 59 q:=2147483647; 60 fillchar(s,sizeof(s),0); 61 for j:=(i-1)*size+1 to n do 62 begin 63 inc(s[rank[j]]); 64 if (s[rank[j]]>p) or ((s[rank[j]]=p) and (a[j]<q)) then 65 begin 66 p:=s[rank[j]]; 67 q:=a[j]; 68 end; 69 a1[i,be[j]]:=p; 70 a2[i,be[j]]:=q; 71 end; 72 end; 73 fillchar(s,sizeof(s),255); 74 end; 75 76 function ask(x,y:longint):longint; 77 var i,p,q,w:longint; 78 begin 79 if be[x]=be[y] then 80 begin 81 p:=0; 82 q:=2147483647; 83 for i:=x to y do 84 begin 85 if s[rank[i]]=-1 then s[rank[i]]:=0; 86 inc(s[rank[i]]); 87 if (s[rank[i]]>p) or (s[rank[i]]=p) and (a[i]<q) then 88 begin 89 p:=s[rank[i]]; 90 q:=a[i]; 91 end; 92 end; 93 clear(x,y); 94 exit(q); 95 end 96 else begin 97 p:=a1[be[x]+1,be[y]-1]; 98 q:=a2[be[x]+1,be[y]-1]; 99 for i:=x to be[x]*size do 100 begin 101 if s[rank[i]]=-1 then s[rank[i]]:=f[be[y]-1,rank[i]]-f[be[x],rank[i]]; 102 inc(s[rank[i]]); //关键 103 if (s[rank[i]]>p) or (s[rank[i]]=p) and (a[i]<q) then 104 begin 105 p:=s[rank[i]]; 106 q:=a[i]; 107 end; 108 end; 109 for i:=(be[y]-1)*size+1 to y do 110 begin 111 if s[rank[i]]=-1 then s[rank[i]]:=f[be[y]-1,rank[i]]-f[be[x],rank[i]]; 112 inc(s[rank[i]]); 113 if (s[rank[i]]>p) or (s[rank[i]]=p) and (a[i]<q) then 114 begin 115 p:=s[rank[i]]; 116 q:=a[i]; 117 end; 118 end; 119 clear(x,be[x]*size); //一点常数优化,不用fillchar 120 clear((be[y]-1)*size+1,y); 121 exit(q); 122 end; 123 end; 124 125 begin 126 readln(n,q); 127 size:=trunc(sqrt(n)); 128 for i:=1 to n do 129 begin 130 read(a[i]); 131 be[i]:=(i-1) div size+1; 132 b[i]:=a[i]; 133 c[i]:=i; 134 end; 135 tot:=n div size; 136 if n mod size<>0 then inc(tot); 137 sort(1,n); 138 m:=1; 139 rank[c[1]]:=1; 140 for i:=2 to n do 141 begin 142 if b[i]<>b[i-1] then inc(m); 143 rank[c[i]]:=m; 144 end; 145 pre; 146 t:=0; 147 ans:=0; 148 for i:=1 to q do 149 begin 150 readln(x,y); 151 x:=(x+ans-1) mod n+1; 152 y:=(y+ans-1) mod n+1; 153 if x>y then swap(x,y); 154 ans:=ask(x,y); 155 writeln(ans); 156 end; 157 end.