BZOJ2724: [Violet 6]蒲公英
n<=40000个数,在线问m<=50000次区间众数,数字Ai<=1e9。
重要结论:$mode(a \cup b)\epsilon mode(a) \cup b$,显然。
用分块做,对区间[L,R]取众数,就先对他们跨过的块O(1)取答案--预处理A(i,j)表示块i到块j的众数即可,然后对两边零散的数和他们跨过的块的那个众数都算一次在[L,R]的出现次数即可。
现在问题就是算某个数在某个区间出现次数。
方法一:把每个数的位置取出来二分!n*sqrt(n)*logn,慢
方法二:前缀思想!计算[1,R]的减去[1,L-1]的,问题再次转化。然后[1,R]的某个数的出现次数,可以先预处理B(i,j)表示前i个块数j出现次数,然后C(i,j,x)表示块i前j个数中数x出现多少次,这里要在每个块里再离散化一次,D(i,j)表示数i在块j的C数组中的x是多少,因为x太大C开不下。。
其实C和D是多余的,前后两段数直接开桶记录然后用B来算中间就行了。
1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 #include<stdlib.h> 5 #include<math.h> 6 //#include<bitset> 7 //#include<iostream> 8 using namespace std; 9 10 int n,m,q; 11 #define maxn 41011 12 #define maxm 311 13 int lisan[maxn],li=0,bud[maxn]; 14 int most[maxm][maxm],num[maxm],lnum,s[maxm][maxn],cnt[maxm][maxm][maxm],pos[maxn][maxm],bel[maxn],tot,a[maxn]; 15 16 int calc(int p,int v) {if (!p) return 0;return s[bel[p]-1][v]+cnt[bel[p]][p-(bel[p]-1)*m][pos[v][bel[p]]];} 17 int main() 18 { 19 scanf("%d%d",&n,&q); 20 m=(int)sqrt(n); 21 for (int i=1;i<=n;i++) bel[i]=(i-1)/m+1; 22 tot=bel[n]; 23 for (int i=1;i<=n;i++) scanf("%d",&a[i]),lisan[++li]=a[i]; 24 sort(lisan+1,lisan+1+li); li=unique(lisan+1,lisan+1+li)-lisan-1; 25 for (int i=1;i<=n;i++) a[i]=lower_bound(lisan+1,lisan+1+li,a[i])-lisan; 26 for (int i=1,now=1;i<=n;i+=m,now++) 27 { 28 memset(bud,0,sizeof(bud)); 29 int Max=0; 30 for (int j=i;j<=n;j++) 31 { 32 bud[a[j]]++; 33 if (bud[a[j]]>bud[Max] || (bud[a[j]]==bud[Max] && a[j]<Max)) Max=a[j]; 34 if (bel[j]!=bel[j+1]) most[now][bel[j]]=Max; 35 } 36 } 37 for (int i=1,now=1;i<=n;i+=m,now++) 38 { 39 lnum=0; 40 for (int j=i;bel[j]==bel[i];j++) num[++lnum]=a[j]; 41 sort(num+1,num+1+lnum); lnum=unique(num+1,num+1+lnum)-num-1; 42 for (int j=i;bel[j]==bel[i];j++) 43 { 44 for (int k=i;k<j;k++) cnt[now][j-i+1][pos[a[k]][now]]=cnt[now][j-i][pos[a[k]][now]]; 45 pos[a[j]][now]=lower_bound(num+1,num+1+lnum,a[j])-num, 46 cnt[now][j-i+1][pos[a[j]][now]]++; 47 } 48 for (int j=1,r=min(now*m,n)-(now-1)*m;j<=li;j++) 49 s[now][j]=s[now-1][j]+cnt[now][r][pos[j][now]]; 50 } 51 int x,y,last=0; 52 memset(bud,0,sizeof(bud)); 53 while (q--) 54 { 55 scanf("%d%d",&x,&y); 56 x=(x+last-1)%n+1,y=(y+last-1)%n+1; 57 if (x>y) {int t=x;x=y;y=t;} 58 if (bel[x]==bel[y]) 59 { 60 int Max=0; 61 for (int i=x;i<=y;i++) 62 { 63 bud[a[i]]++; 64 if (bud[a[i]]>bud[Max] || (bud[a[i]]==bud[Max] && a[i]<Max)) Max=a[i]; 65 } 66 printf("%d\n",(last=lisan[Max])); 67 for (int i=x;i<=y;i++) bud[a[i]]--; 68 } 69 else 70 { 71 int Max=most[bel[x]+1][bel[y]-1],tot=calc(y,Max)-calc(x-1,Max); 72 for (int j=x,tmp;bel[j]==bel[x];j++) 73 { 74 tmp=calc(y,a[j])-calc(x-1,a[j]); 75 if (tmp>tot || (tmp==tot && a[j]<Max)) Max=a[j],tot=tmp; 76 } 77 for (int j=y,tmp;bel[j]==bel[y];j--) 78 { 79 tmp=calc(y,a[j])-calc(x-1,a[j]); 80 if (tmp>tot || (tmp==tot && a[j]<Max)) Max=a[j],tot=tmp; 81 } 82 printf("%d\n",(last=lisan[Max])); 83 } 84 } 85 return 0; 86 }