[分块][离散化] Bzoj P2724 蒲公英
Description
Input
修正一下
l = (l_0 + x – 1) mod n + 1, r = (r_0 + x – 1) mod n + 1
Output
HINT
修正下:
n <= 40000, m <= 50000
题解
- 就是要求区间众数,可以先离散化
-
我们可以预处理f(i,j)表示第 i 块到第 j 块的众数
-
那么只要能快速得出一个数在某个区间内出现次数即可,每次只要比较至多2√n+1个元素的出现次数
-
由于没有修改,只要离散化以后,给每个数 x 开个vector,按顺序存下 x 出现的位置
-
每次询问 x 时把区间的左右端点放进对应 vector 二分一下即可
代码
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <map> 5 #include <vector> 6 #include <algorithm> 7 using namespace std; 8 const int N=50010; 9 int n,m,K=200,id,v[N],bl[N],f[510][510]; 10 map<int,int>mp; 11 int val[N],cnt[N]; 12 vector<int>Q[N]; 13 int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 17 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 void pre(int x) 21 { 22 memset(cnt,0,sizeof(cnt)); int mx=0,ans=0; 23 for (int i=(x-1)*K+1;i<=n;i++) 24 { 25 cnt[v[i]]++; 26 int t=bl[i]; 27 if (cnt[v[i]]>mx||(cnt[v[i]]==mx&&val[v[i]]<val[ans])) ans=v[i],mx=cnt[v[i]]; 28 f[x][t]=ans; 29 } 30 } 31 int query(int l,int r,int x) { return upper_bound(Q[x].begin(),Q[x].end(),r)-lower_bound(Q[x].begin(),Q[x].end(),l); } 32 int query(int a,int b) 33 { 34 int ans,mx; 35 ans=f[bl[a]+1][bl[b]-1],mx=query(a,b,ans); 36 for (int i=a;i<=min(bl[a]*K,b);i++) 37 { 38 int t=query(a,b,v[i]); 39 if (t>mx||(t==mx&&val[v[i]]<val[ans])) ans=v[i],mx=t; 40 } 41 if (bl[a]!=bl[b]) 42 for (int i=(bl[b]-1)*K+1;i<=b;i++) 43 { 44 int t=query(a,b,v[i]); 45 if (t>mx||(t==mx&&val[v[i]]<val[ans])) ans=v[i],mx=t; 46 } 47 return ans; 48 } 49 int main() 50 { 51 n=read(),m=read(); int ans=0; 52 for (int i=1;i<=n;i++) 53 { 54 v[i]=read(); 55 if (!mp[v[i]]) mp[v[i]]=++id,val[id]=v[i]; 56 v[i]=mp[v[i]],Q[v[i]].push_back(i); 57 } 58 for (int i=1;i<=n;i++) bl[i]=(i-1)/K+1; 59 for (int i=1;i<=bl[n];i++) pre(i); 60 for (int a,b;m;m--) 61 { 62 a=read(),b=read(); 63 a=(a+ans-1)%n+1,b=(b+ans-1)%n+1; 64 if (a>b) swap(a,b); 65 printf("%d\n",ans=val[query(a,b)]); 66 } 67 }