BZOJ 2724 [Violet 6]蒲公英(分块)

题意

在线区间众数

思路

预处理出 f[i][j] 即从第 i 块到第 j 块的答案。
对于每个询问,中间的整块直接用预处理出的,两端的 sqrtn 级别的数暴力做,用二分查找它们出现的次数。
每次询问的复杂度是 sqrtn * logn 。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<cstdio>
  5 #include<algorithm>
  6 #include<vector>
  7 using namespace std;
  8 const int N=100010;
  9 vector<int> vec[N];
 10 int n,m,a[N],b[N],block[N],ans,Block,L[N],R[N],cnt[N],top,stack[N],f[700][700],ff[700][700],tot;
 11 int find1(int x,int y){
 12     int l=0;int r=vec[x].size()-1;
 13     int tmp=-9999999;
 14     while(l<=r){
 15         int mid=(l+r)>>1;
 16         if(vec[x][mid]<=y){
 17             tmp=mid;
 18             l=mid+1;
 19         }
 20         else r=mid-1;
 21     }
 22     return tmp;
 23 }
 24 int find2(int x,int y){
 25     int l=0;int r=vec[x].size()-1;
 26     int tmp=9999999;
 27     while(l<=r){
 28         int mid=(l+r)>>1;
 29         if(vec[x][mid]>=y){
 30             tmp=mid;
 31             r=mid-1;
 32         }
 33         else l=mid+1;
 34     }
 35     return tmp;
 36 }
 37 int main(){
 38     scanf("%d%d",&n,&m);
 39     Block=sqrt(n);
 40     for(int i=1;i<=n;i++){
 41         scanf("%d",&a[i]);
 42         b[i]=a[i];
 43     }
 44     sort(b+1,b+1+n);
 45     int num=unique(b+1,b+1+n)-b-1;
 46     for(int i=1;i<=n;i++){
 47         a[i]=lower_bound(b+1,b+1+num,a[i])-b;
 48         block[i]=(i-1)/Block+1;
 49         vec[a[i]].push_back(i);
 50         if(!L[block[i]])L[block[i]]=i;
 51         R[block[i]]=i;
 52     }
 53     for(int i=1;i<=block[n];i++){
 54         tot=0;
 55         for(int j=L[i];j<=n;j++){
 56             cnt[a[j]]++;
 57             if(tot<=cnt[a[j]]){
 58                 if(cnt[a[j]]>tot)ans=b[a[j]];
 59                 else ans=min(ans,b[a[j]]);
 60                 tot=cnt[a[j]];
 61             }
 62             f[i][block[j]]=tot;
 63             ff[i][block[j]]=ans;
 64         }
 65         for(int j=L[i];j<=n;j++){
 66             cnt[a[j]]=0;
 67         }
 68     }
 69     ans=0;
 70     for(int i=1;i<=m;i++){
 71         int l,r;
 72         scanf("%d%d",&l,&r);
 73         l=(l+ans-1)%n+1;r=(r+ans-1)%n+1;
 74         if(l>r)swap(l,r);
 75         if(block[l]+1>=block[r]){
 76             tot=0;
 77             ans=0;
 78             for(int i=l;i<=r;i++){
 79                 cnt[a[i]]++;
 80                 if(tot<=cnt[a[i]]){
 81                     if(cnt[a[i]]>tot)ans=b[a[i]];
 82                     else ans=min(ans,b[a[i]]);
 83                     tot=cnt[a[i]];
 84                 }
 85             }
 86             for(int i=l;i<=r;i++){
 87                 cnt[a[i]]=0;
 88             }
 89         }
 90         else{
 91             top=0;
 92             tot=f[block[l]+1][block[r]-1];
 93             ans=ff[block[l]+1][block[r]-1];
 94             for(int i=l;i<=R[block[l]];i++){
 95                 cnt[a[i]]++;
 96                 if(cnt[a[i]]==1)stack[++top]=a[i];
 97             }
 98             for(int i=L[block[r]];i<=r;i++){
 99                 cnt[a[i]]++;
100                 if(cnt[a[i]]==1)stack[++top]=a[i];
101             }
102             while(top){
103                 int z=stack[top--];
104                 int tmp=max(0,find1(z,L[block[r]]-1)-find2(z,R[block[l]]+1)+1);
105                 if(tot<=cnt[z]+tmp){
106                     if(cnt[z]+tmp>tot)ans=b[z];
107                     else ans=min(ans,b[z]);
108                     tot=cnt[z]+tmp;
109                 }
110                 cnt[z]=0;
111             }
112         }
113         printf("%d\n",ans); 
114     }
115     return 0;
116 }

 

posted @ 2018-08-14 22:36  Xu-daxia  阅读(108)  评论(0编辑  收藏  举报