[BZOJ2724] [Violet 6]蒲公英
题目链接
BZOJ.
洛谷.
Solution
神仙分块。
首先分成\(\sqrt{n}\)大小的块,先预处理\(sum[i][v]\)表示值为\(v\)的在前\(i\)个块出现了多少次,离散化之后这部分\(O(n\sqrt{n})\)。
然后预处理\(f[i][j]\)表示第\(i\)到第\(j\)个块的众数和出现次数,这个处理可以仿照区间\(dp\),假设我们处理好了\(f[i][j-1]\),那么考虑最后一个块的贡献,众数只有可能是前面块的众数或者是后面多出来的数。
那么可以开个桶\(s[i]\)表示值为\(i\)的出现了多少次,那么先用前面处理出来的前缀和把前\(i\sim j-1\)的块统计好,然后枚举第\(j\)个块的所有值,更新\(s[i]\)顺便处理答案。
那么询问也同样的处理,询问可以分成三块,中间的整块和两边的零碎块,整块直接前缀和加预处理出来的\(f\)更新,零碎的枚举所有值。
总复杂度\(O(n\sqrt{n})\)。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define ll long long
const int maxn = 4e4+10;
const int inf = 1e9;
const lf eps = 1e-8;
int f[202][202],h[202][202],g[202][maxn],n,m,v[maxn],R[maxn],s[maxn],st[maxn],ed[maxn],bel[maxn];
int solve(int l,int r) {
if(bel[l]==bel[r]) {
int res=0,num=0;
for(int i=l;i<=r;i++) s[v[i]]=0;
for(int i=l;i<=r;i++) {
s[v[i]]++;
if(s[v[i]]>num||(s[v[i]]==num&&v[i]<res)) num=s[v[i]],res=v[i];
}return res;
}
int res=f[bel[l]+1][bel[r]-1],num=h[bel[l]+1][bel[r]-1];
for(int i=l;i<=ed[bel[l]];i++) s[v[i]]=0;
for(int i=st[bel[r]];i<=r;i++) s[v[i]]=0;
for(int i=l;i<=ed[bel[l]];i++)
if(!s[v[i]]) s[v[i]]=g[bel[r]-1][v[i]]-g[bel[l]][v[i]];
for(int i=st[bel[r]];i<=r;i++)
if(!s[v[i]]) s[v[i]]=g[bel[r]-1][v[i]]-g[bel[l]][v[i]];
for(int i=l;i<=ed[bel[l]];i++) {
s[v[i]]++;
if(s[v[i]]>num||(s[v[i]]==num&&v[i]<res)) num=s[v[i]],res=v[i];
}
for(int i=st[bel[r]];i<=r;i++) {
s[v[i]]++;
if(s[v[i]]>num||(s[v[i]]==num&&v[i]<res)) num=s[v[i]],res=v[i];
}return res;
}
int main() {
read(n),read(m);int b=ceil(sqrt(n));
for(int i=1;i<=n;i++) read(v[i]),R[i]=v[i];
sort(R+1,R+n+1);int M=unique(R+1,R+n+1)-R-1;
for(int i=1;i<=n;i++) v[i]=lower_bound(R+1,R+M+1,v[i])-R;
for(int i=1;i<=n;i++) bel[i]=(i-1)/b+1;int cnt=bel[n];
for(int i=1;i<=n;i++) st[bel[i]]=bel[i]==bel[i-1]?st[bel[i-1]]:i;
for(int i=n;i;i--) ed[bel[i]]=bel[i]==bel[i+1]?ed[bel[i+1]]:i;
for(int i=1;i<=n;i++)
for(int j=bel[i];j<=cnt;j++) g[j][v[i]]++;
for(int x=1;x<=cnt;x++) {
int res=0,num=0;
for(int i=st[x];i<=ed[x];i++) s[v[i]]=0;
for(int i=st[x];i<=ed[x];i++) {
s[v[i]]++;
if(s[v[i]]>num||(s[v[i]]==num&&v[i]<res)) res=v[i],num=s[v[i]];
}f[x][x]=res,h[x][x]=num;
}
for(int len=2;len<=cnt;len++)
for(int j=1;j<=cnt-len+1;j++) {
int l=j,r=j+len-1;f[l][r]=f[l][r-1],h[l][r]=h[l][r-1];
for(int i=st[r];i<=ed[r];i++) s[v[i]]=0;
for(int i=st[r];i<=ed[r];i++)
if(!s[v[i]]) s[v[i]]=g[r-1][v[i]]-g[l-1][v[i]];
for(int i=st[r];i<=ed[r];i++) {
s[v[i]]++;
if(s[v[i]]>h[l][r]||(s[v[i]]==h[l][r]&&v[i]<f[l][r])) f[l][r]=v[i],h[l][r]=s[v[i]];
}
}
int lstans=0;
for(int i=1,l,r;i<=m;i++) {
read(l),read(r);
l=(l+lstans-1)%n+1,r=(r+lstans-1)%n+1;
if(l>r) swap(l,r);
write(lstans=R[solve(l,r)]);
}
return 0;
}