BZOJ 2724--蒲公英(分块)
2724: [Violet 6]蒲公英
Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 2507 Solved: 869
[Submit][Status][Discuss]
Description
Input
修正一下
l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1
Output
Sample Input
6 3
1 2 3 2 1 2
1 5
3 6
1 5
1 2 3 2 1 2
1 5
3 6
1 5
Sample Output
1
2
1
2
1
HINT
数据范围:
n <= 40000, m <= 50000
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=2724
Solution
经典的分块,众数是不可合并的,所以不能用线段树来维护。。。
这时候就要用分块啦。。。。
一个定理:两个集合的众数一定包含于一个集合和另一个集合的众数中。
然后预处理出第 i 块 到 第 j 块的众数,还有位置 i 到 j 的某种元素的个数。。
之后用分块维护就好了。。。
代码
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<map> #define N 40050 #define LL long long using namespace std; inline int Read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,Q,e,m,cnt=0,x=0,t=0; int a[N],b[N],g[N],sum[N],f[250][250],vis[N]; map<int,int>mp; vector<int> q[N]; void reset(int k){ int mx=0,s=0; for(int i=1;i<=cnt;i++) sum[i]=0; for(int i=(k-1)*e+1;i<=n;i++) { sum[a[i]]++; if(sum[a[i]]>sum[mx] || (sum[a[i]]==sum[mx]&&b[a[i]]<b[mx])) mx=a[i]; f[k][g[i]]=mx; } } int calc(int h,int c){ int l=0,r=q[c].size()-1,mid; if(q[c][l]>h) return 0;if(q[c][r]<=h) return q[c].size(); while(l!=r){ mid=(l+r+1)>>1; if(q[c][mid]<=h) l=mid; else r=mid-1; } return l+1; } void solve(int l,int r,int K){ int now; x=0;t=0; if(g[l]==g[r]){ for(int i=l;i<=r;i++){ if(vis[a[i]]==K) continue;vis[a[i]]=K; now=calc(r,a[i])-calc(l-1,a[i]); if(now>t || (now==t && b[a[i]]<b[x])){x=a[i];t=now;} } x=b[x]; printf("%d\n",x); return; } for(int i=l;i<=e*(g[l]);i++) { if(vis[a[i]]==K) continue;vis[a[i]]=K; now=calc(r,a[i])-calc(l-1,a[i]); if(now>t || (now==t && b[a[i]]<b[x])){x=a[i];t=now;} } for(int i=(g[r]-1)*e+1;i<=r;i++) { if(vis[a[i]]==K) continue;vis[a[i]]=K; now=calc(r,a[i])-calc(l-1,a[i]); if(now>t || (now==t && b[a[i]]<b[x])){x=a[i];t=now;} } if(g[r]-1>=g[l]+1) { int j=f[g[l]+1][g[r]-1]; now=calc(r,j)-calc(l-1,j); if(now>t || (now==t && b[j]<b[x])){x=j;t=now;} } x=b[x]; printf("%d\n",x); return; } int main(){ char ch; LL l,r; n=Read();Q=Read();e=ceil(sqrt(n)); for(int i=1;i<=n;i++) { a[i]=Read(); if(!mp[a[i]]){ mp[a[i]]=++cnt; b[cnt]=a[i]; } a[i]=mp[a[i]]; q[a[i]].push_back(i); g[i]=(i+e-1)/e; } m=g[n]; for(int i=1;i<=m;i++) reset(i); for(int i=1;i<=Q;i++){ l=(Read()+x-1)%n+1;r=(Read()+x-1)%n+1; if(l>r) swap(l,r); solve(l,r,i); } return 0; }
This passage is made by Iscream-2001.