1. 程式人生 > >[日常摸魚]bzoj2724蒲公英-分塊

[日常摸魚]bzoj2724蒲公英-分塊

== pos gpo lower 兩個 ret 出現 離散化 turn

區間眾數經典題~

http://begin.lydsy.com/JudgeOnline/problem.php?id=4839
這裏可以提交~

題意大概就是沒有修改的詢問區間眾數,如果有一樣的輸出最小的,強制在線,$n \leq 4*10^4,a_i \leq 10^9$。


log數據結構腦補一遍好像沒什麽可以做的,數據範圍我們可以分塊!

不過分塊之前肯定要離散化一下,而且還要保存離散化前的數據(因為要回答的是出現最多的數),離散化的方法在上一篇博客裏面~

假設分成$L$塊,每塊大小$s=\lfloor n/L \rfloor$,預處理出每一塊的起點和終點$st[],ed[]$,然後再預處理出$O(L^2)$個連續的塊裏的答案(每種顏色的出現次數,最大次數和對應的顏色),這樣預處理的復雜度是$O(n*L^2)$。

然後對於一個區間的詢問$[x,y]$,一定能拆成連續的若幹個塊(假設對應的塊是$[p,q]$)和至多兩個不完整的塊,對於中間連續的塊直接用我們之前預處理的答案。兩邊的暴力更新。

一種更新方法是把兩邊的顏色都加到中間完整的一段去,然後更新答案,更新完之後再減回去。復雜度$O(\frac{mn}{L})$,於是總復雜度$O(n*L^2+\frac{mn}{L})$,$m,n$同階,均值不等式告訴我們當$L=n^{\frac{1}{3}}$的時候復雜度取最小值為$O(n^{\frac{5}{3}})$

#include<cstdio>
#include<algorithm>
#include
<cstring> #include<cmath> #define rep(i,n) for(register int i=1;i<=n;i++) #define REP(i,a,b) for(register int i=a;i<=b;i++) #define debug(x) printf("%s = %d , ",#x,x) using namespace std; const int T=40; const int N=40005; inline int read() { int s=0,f=1;char c=getchar(); while
(c<0||c>9){if(c==-)f=0;c=getchar();} while(c>=0&&c<=9){s=s*10+c-0;c=getchar();} return f?s:-s; } int n,Q,L,s,ans,cnt,tot,num,p,q; int w[N],tw[N],v[N],b[N],c[T][T][N],f[T][T],d[T][T],st[T],ed[T]; inline void prework() { n=read();Q=read(); rep(i,n)w[i]=read(); L=(int)pow(n,1.0/3.0); if(L)s=n/L; rep(i,L)st[i]=(i-1)*s+1,ed[i]=i*s; if(ed[L]!=n)st[L+1]=ed[L]+1,ed[++L]=n; memcpy(tw,w,sizeof tw);sort(tw+1,tw+n+1); rep(i,n)if(i==1||tw[i]!=tw[i-1])v[++tot]=tw[i]; rep(i,n)b[i]=lower_bound(v+1,v+tot+1,w[i])-v; REP(i,1,L)REP(j,i,L) { rep(k,tot)c[i][j][k]=c[i][j-1][k]; REP(k,st[j],ed[j])c[i][j][b[k]]++; rep(k,tot)if(c[i][j][k]>f[i][j]||(c[i][j][k]==f[i][j]&&tw[k]<d[i][j])) f[i][j]=c[i][j][k],d[i][j]=k; } } inline void updata(int i) { c[p][q][b[i]]++; if(c[p][q][b[i]]>cnt||(c[p][q][b[i]]==cnt&&b[i]<num))cnt=c[p][q][b[i]],num=b[i]; } inline int solve(int x,int y) { if(x>y)swap(x,y); int l,r; for(register int i=1;i<=L;i++)if(x<=ed[i]){l=i;break;} for(register int i=L;i>=1;i--)if(y>=st[i]){r=i;break;} if(l+1<=r-1)p=l+1,q=r-1; else p=q=0; cnt=f[p][q];num=d[p][q]; if(l==r) { REP(i,x,y)updata(i); REP(i,x,y)c[p][q][b[i]]--; }else { REP(i,x,ed[p-1])updata(i); REP(i,st[q+1],y)updata(i); REP(i,x,ed[p-1])c[p][q][b[i]]--; REP(i,st[q+1],y)c[p][q][b[i]]--; } return v[num]; } int main() { prework(); rep(i,Q) { int l,r; l=read();r=read(); ans=solve((l+ans-1)%n+1,(r+ans-1)%n+1); printf("%d\n",ans); } return 0; }

[日常摸魚]bzoj2724蒲公英-分塊