1. 程式人生 > >BZOJ2724: [Violet 6]蒲公英

BZOJ2724: [Violet 6]蒲公英

pan def span -- space %d sed scanf play

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 }
View Code

BZOJ2724: [Violet 6]蒲公英