BZOJ2724 蒲公英

Description

Input

修正一下

l = (l_0 + x – 1) mod n + 1, r = (r_0 + x – 1) mod n + 1

Output

HINT

修正下:

n <= 40000, m <= 50000


解析:

     分块果然还是不简单啊。。。

     这是一道很经典的在线求区间众数的题,因为众数不具有“区间可加性”,所以用树状数组或

者线段树就会很麻烦,所以我们可以考虑一下分块。

     把序列分成M块,则每块长度len=N/M。对于每个寻味[l,r],设l处于第p块,r处于第q块。我们把区间[l,r]分为三部分:

      1.开头不足一整段的[l,L)。

      2.第p+1—q-1块构成的区间[L,R]。

      3.结尾不足一整段的(R,r]。

      显然[l,r]中的众数只可能来自于一下两种情况:

      1.区间[L,R]的众数。

      2.出现在[l,L)与(R,r]之间的数。

      我们令f[i][j][k]表示第i—j块数字k出现的次数,num[i][j]表示第i—j块中众数,

sum[i][j]表示第i—j块中众数出现的次数。因为由题意可知a[i]最大能达到1e9,如果直接存入f数

组一定会炸掉,所以我们必须对数据离散化

       预处理完f、num和sum后。对于每个询问,l属于p段,r属于q段。

       1.如果l,r不属于同一段,则将首尾不足一段的数加入到f[p+1][q-1]中并更新答案,然后再将f[p+1][q-1]还原。

       2.如果l,r属于同一段,则将l—r的数加入到f[0][0]中并更新答案,然后再将f[0][0]还原。


代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int Max=40100;
int n,m,len,q,maxsum,maxnum,ans,LL,RR,tot;
int f[40][40][Max],L[Max],R[Max],sum[40][40],num[40][40];
int a[Max],b[Max],c[Max];
inline int get_int()
{
   int x=0,f=1;
   char c;
   for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
   if(c=='-') {f=-1;c=getchar();}
   for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
   return x*f;
}
inline void pre()
{
   m=(int)pow(n*1.0,1.0/3);
   len=n/m;
   for(int i=1;i<=m;i++)
   {
     L[i]=(i-1)*len+1;
     R[i]=min(i*len,n);
   }
   if(R[m]<n) {m++;L[m]=R[m-1]+1;R[m]=n;}
   memcpy(b,a,sizeof(a));
   sort(b+1,b+1+n);
   int size=unique(b+1,b+1+n)-b-1;
   for(int i=1;i<=size;i++) c[i]=b[i];
   for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+size,a[i])-b;
   for(int i=1;i<=m;i++)
     for(int j=i;j<=m;j++)
     {
       for(int k=L[i];k<=R[j];k++) f[i][j][a[k]]++;
       for(int k=1;k<=size;k++)
         if((f[i][j][k]>sum[i][j])||(k<num[i][j]&&f[i][j][k]==sum[i][j]))
         {
           sum[i][j]=f[i][j][k];
           num[i][j]=k;
         }
     }
}
inline void update(int i)
{
   f[LL][RR][a[i]]++;
   if((f[LL][RR][a[i]]>maxsum)||(a[i]<maxnum&&f[LL][RR][a[i]]==maxsum)) {maxsum=f[LL][RR][a[i]];maxnum=a[i];}
}
inline int solve(int x,int y)
{
   int l,r;
   if(x>y) swap(x,y);
   for(int i=1;i<=m;i++) if(x<=R[i]) {l=i;break;}
   for(int i=m;i>=1;i--) if(y>=L[i]) {r=i;break;}
   if(l+1<=r-1) {LL=l+1;RR=r-1;} else LL=RR=0;
   maxsum=sum[LL][RR];maxnum=num[LL][RR];
   if(l==r)
   {
   	 for(int i=x;i<=y;i++) update(i);
   	 for(int i=x;i<=y;i++) f[LL][RR][a[i]]--;
   }
   else
   {
   	 for(int i=x;i<=R[l];i++) update(i);
   	 for(int i=L[r];i<=y;i++) update(i);
   	 for(int i=x;i<=R[l];i++) f[LL][RR][a[i]]--;
   	 for(int i=L[r];i<=y;i++) f[LL][RR][a[i]]--;
   }
   return c[maxnum];
}
int main()
{
   freopen("dandelion.in","r",stdin);
   freopen("dandelion.out","w",stdout);
   n=get_int();
   q=get_int();
   for(int i=1;i<=n;i++) a[i]=get_int();
   pre();
   while(q--)
   {
   	 int x=get_int(),y=get_int();
   	 ans=solve((x+ans-1)%n+1,(y+ans-1)%n+1);
   	 cout<<ans<<"\n";
   }
   return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/80083645