分块大法好!
首先预处理第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.
View Code

 



 

posted on 2014-12-25 20:38  acphile  阅读(169)  评论(0编辑  收藏  举报