题解报告——蒲公英
题目背景
亲爱的哥哥:
你在那个城市里面过得好吗?
我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的……
最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢!
哥哥你要快点回来哦!
爱你的妹妹 Violet
Azure 读完这封信之后微笑了一下。
“蒲公英吗……”
题目描述
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
为了简化起见,我们把所有的蒲公英看成一个长度为n的序列 (a1,a2..an)(a_1,a_2..a_n)(a1,a2..an),其中 aia_iai 为一个正整数,表示第i棵蒲公英的种类编号。
而每次询问一个区间 [l,r],你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
注意,你的算法必须是在线的
输入输出格式
输入格式:
第一行两个整数 n,m ,表示有n株蒲公英,m 次询问。
接下来一行n个空格分隔的整数 aia_iai ,表示蒲公英的种类
再接下来m 行每行两个整数 l0,r0l_0,r_0l0,r0,我们令上次询问的结果为 x(如果这是第一次询问, 则 x=0)。
令 l=(l0+x−1)modn+1,r=(r0+x−1)modn+1l=(l_0+x-1)\bmod n + 1,r=(r_0+x-1) \bmod n + 1l=(l0+x−1)modn+1,r=(r0+x−1)modn+1,如果 l>r,则交换 l,r 。
最终的询问区间为[l,r]。
输出格式:
输出m 行。每行一个整数,表示每次询问的结果。
输入输出样例
说明
对于 20% 的数据,保证 1≤n,m≤30001\le n,m \le 30001≤n,m≤3000。
对于 100% 的数据,保证 1≤n≤40000,1≤m≤50000,1≤ai≤1091\le n \le 40000,1\le m \le 50000,1\le a_i \le 10^91≤n≤40000,1≤m≤50000,1≤ai≤109。
【思路分析】
分块好题,分块大法好,暴力操标算。。。囧rz!!!
这道题看得出就是一道区间求众数的题目。
大致思路是这样的,首先我们要充分发挥分块暴力大法好的精神
先暴力预处理出每个块内每种蒲公英的个数,
然后求出对每个块而言的前缀和,
于是这样我们就可以区间查询任意两个块之间每种蒲公英的数量了
然后我们预处理出任意两个块之间的众数
最后对于每组询问,我们先找到夹在它们中间的块,
如果两个块相差超过了1,那么我们先取出中间块的众数,作为我们的answer,然后对旁边两个块暴力处理众数(此处注意判断时要加上中间的蒲公英)。
如果这个两个块r-l<=1,那么我们暴力求众数。。。
最后记得离散化一下即可。。。
【代码实现】
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cctype> 5 #include<cmath> 6 using namespace std; 7 inline void read(int &x) 8 { 9 int f;char ch; 10 while(!isdigit(ch=getchar())&&ch!='-'); ch=='-'?(f=-1,x=0):(f=1,x=ch-'0'); 11 while(isdigit(ch=getchar())) x=x*10+ch-'0';x=x*f; 12 } 13 const int N=4e4+5,M=205; 14 struct sd{ 15 int id,w; 16 }num[N]; 17 int rank[N],back[N],n,nn,m,tot,sqr; 18 int sum[M][N],mx[M][M],time[N],lastans; 19 bool cmp(sd a,sd b) {return a.w<b.w;} 20 int GG(int l,int r) 21 { 22 int now=0; 23 for(int i=l;i<=r;i++) 24 { 25 time[rank[i]]++; 26 if(time[now]<time[rank[i]]) now=rank[i]; 27 if(time[now]==time[rank[i]]&&rank[i]<now) now=rank[i]; 28 } 29 return now; 30 } 31 int ask(int l,int r) 32 { 33 int ll=(l-1)/sqr+1,rr=(r-1)/sqr+1,lr,rl,mx1,mx2; 34 if(rr-ll<=1) 35 { 36 int res=GG(l,r); 37 for(int i=l;i<=r;i++) time[rank[i]]--; 38 return res; 39 } 40 int now=mx[ll+1][rr-1]; 41 lr=ll*sqr,rl=(rr-1)*sqr+1; 42 GG(l,lr),GG(rl,r); 43 for(int i=l;i<=lr;i++) 44 { 45 if(sum[rr-1][now]-sum[ll][now]+time[now]<sum[rr-1][rank[i]]-sum[ll][rank[i]]+time[rank[i]]) now=rank[i]; 46 if(sum[rr-1][now]-sum[ll][now]+time[now]==sum[rr-1][rank[i]]-sum[ll][rank[i]]+time[rank[i]]&&rank[i]<now) now=rank[i]; 47 } 48 for(int i=rl;i<=r;i++) 49 { 50 if(sum[rr-1][now]-sum[ll][now]+time[now]<sum[rr-1][rank[i]]-sum[ll][rank[i]]+time[rank[i]]) now=rank[i]; 51 if(sum[rr-1][now]-sum[ll][now]+time[now]==sum[rr-1][rank[i]]-sum[ll][rank[i]]+time[rank[i]]&&rank[i]<now) now=rank[i]; 52 } 53 for(int i=l;i<=lr;i++) time[rank[i]]--; 54 for(int i=rl;i<=r;i++) time[rank[i]]--; 55 return now; 56 } 57 int main() 58 { 59 read(n),read(m); 60 sqr=sqrt(n),nn=(n-1)/sqr+1; 61 for(int i=1;i<=n;i++) read(num[i].w),num[i].id=i; 62 sort(num+1,num+1+n,cmp); 63 for(int i=1;i<=n;i++) 64 { 65 if(num[i].w!=num[i-1].w) tot++; 66 rank[num[i].id]=tot,back[tot]=num[i].w; 67 } 68 for(int i=1;i<=n;i++) 69 for(int j=(i-1)/sqr+1;j<=nn;j++) 70 sum[j][rank[i]]++; 71 for(int i=1;i<=nn;i++) 72 { 73 int l,r; 74 for(int j=i;j<=nn;j++) 75 { 76 mx[i][j]=mx[i][j-1]; 77 l=(j-1)*sqr+1,r=j*sqr; 78 for(int id=l;id<=r;id++) 79 { 80 time[rank[id]]++; 81 if(sum[j-1][rank[id]]-sum[i-1][rank[id]]+time[rank[id]]>sum[j-1][mx[i][j]]-sum[i-1][mx[i][j]]+time[mx[i][j]]) 82 mx[i][j]=rank[id]; 83 if(sum[j-1][rank[id]]-sum[i-1][rank[id]]+time[rank[id]]==sum[j-1][mx[i][j]]-sum[i-1][mx[i][j]]+time[mx[i][j]]&&rank[id]<mx[i][j]) 84 mx[i][j]=rank[id]; 85 } 86 for(int id=l;id<=r;id++) time[rank[id]]--; 87 } 88 } 89 /*for(int i=1;i<=nn;i++) 90 for(int j=i;j<=nn;j++) printf("[%d %d %d]\n",i,j,mx[i][j]);*/ 91 while(m--) 92 { 93 int l,r; 94 read(l),read(r); 95 l=(l+lastans-1)%n+1,r=(r+lastans-1)%n+1; 96 if(l>r) swap(l,r); 97 lastans=back[ask(l,r)]; 98 printf("%d\n",lastans); 99 } 100 return 0; 101 }