洛谷 P4168 [Violet]蒲公英
我真的服了这道题了劳资调了一个下午(怒
题目描述
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
为了简化起见,我们把所有的蒲公英看成一个长度为n的序列(a1,a2..an),其中 ai 为一个正整数,表示第i棵蒲公英的种类编号。
而每次询问一个区间 [l,r],你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
注意,你的算法必须是在线的
输入输出格式
输入格式:
第一行两个整数 n,m ,表示有n株蒲公英,m 次询问。
接下来一行n个空格分隔的整数 ai ,表示蒲公英的种类
再接下来m 行每行两个整数 l0,r0,我们令上次询问的结果为 x(如果这是第一次询问, 则 x=0)。
令 l=(l0+x−1) mod n + 1,r=(r0+x−1) modn + 1,如果 l > r,则交换 l,r 。
最终的询问区间为[l,r]。
输出格式:
输出m 行。每行一个整数,表示每次询问的结果。
输入输出样例
说明
对于 20% 的数据,保证 1≤n,m≤3000。
对于 100% 的数据,保证 1≤n≤40000,1≤m≤50000,1≤ai≤1e9。
这道题我调了好久!!! 就是tag那里搞反了 生气
这道题是一道很经典的分块嘛
预处理出两两块之间的众数什么 而一个区间内的众数有可能是他所包括的区间的众数
也有可能是非整块的数帮助整块内的数反败为胜 所以就需要根$n$扫一遍 然后判断这些颜色是否反败为王就可以了 细节有点多
然后预处理是枚举起点 向后扫一遍 开一个桶存各个颜色的数量 判断与当前最大值谁更大 更新一下就可以了
还有这颜色范围太大了要离散化
代码
#include <bits/stdc++.h> using namespace std; const int N = 4 * 1e4 + 5; const int M = 5 * 1e4 + 2; int n,m,a[N],b[N],blo,k,pos[N]; int cnt[M],s[205][205],sum[205][N],y[M]; bool vis[N]; void Init( ) { scanf("%d%d",& n,& m); blo = sqrt(n); for(int i = 1; i <= n; i++) { scanf("%d",& a[i]); b[i] = a[i]; } sort(b + 1,b + n + 1); k = unique(b + 1,b + n + 1) - b - 1; for(int i = 1;i <= n;i ++) { int ss = a[i]; a[i] = lower_bound(b + 1,b + k + 1,a[i]) - b; y[a[i]] = ss; pos[i] = (i + blo - 1) / blo; if(pos[i] != pos[i - 1] && i != 1) vis[i - 1] = true; } vis[n] = true; for(int i = 1;i <= n;i += blo) { int st = (i + blo - 1) / blo; for(int j = 1;j <= k;j ++) cnt[j] = 0; int ma = 0,ma_col = 0; for(int j = i;j <= n;j ++) { cnt[a[j]] ++; if(cnt[a[j]] >= ma) { if(cnt[a[j]] > ma) ma_col = a[j]; else ma_col = min(ma_col,a[j]); ma = cnt[a[j]]; } if(vis[j]) { int ed = (j + blo - 1) / blo; s[st][ed] = ma_col; } } } for(int i = 1;i <= k;i ++) cnt[i] = 0; for(int i = 1;i <= n;i ++) { cnt[a[i]] ++; if(vis[i]) { int now = (i + blo - 1) / blo; for(int j = 1;j <= k;j ++) sum[now][j] = cnt[j]; } } } void Solve( ) { int L,R,las = 0; while(m --) { int l,r; scanf("%d%d",& l,& r); L = (l + las - 1) % n + 1,R = (r + las - 1) % n + 1; if(L > R) swap(L,R); int lpos = (L + blo - 1) / blo; int rpos = (R + blo - 1) / blo; if(lpos == rpos) { for(int i = L;i <= R;i ++) cnt[a[i]] = 0; int ma = 0,ma_col = 0; for(int i = L;i <= R;i ++) { cnt[a[i]] ++; if(cnt[a[i]] >= ma) { if(cnt[a[i]] > ma) ma_col = a[i]; else ma_col = min(ma_col,a[i]); ma = cnt[a[i]]; } } printf("%d\n",y[ma_col]); las = y[ma_col]; } else { int blo1 = (L + blo - 1) / blo; int blo2 = (R + blo - 1) / blo; int ma_col = 0,ma = 0; bool tag = false; if(blo1 + 1 <= blo2 - 1) { ma_col = s[blo1 + 1][blo2 - 1]; ma = sum[blo2 - 1][ma_col] - sum[blo1][ma_col]; tag = true; } for(int i = L;i <= blo1 * blo;i ++) cnt[a[i]] = 0; for(int i = R;i > (blo2 - 1) * blo;i --) cnt[a[i]] = 0; for(int i = L;i <= blo1 * blo;i ++) cnt[a[i]] ++; for(int i = R;i > (blo2 - 1) * blo;i --) cnt[a[i]] ++; for(int i = L;i <= blo1 * blo;i ++) { int num = cnt[a[i]]; if(tag) num += (sum[blo2 - 1][a[i]] - sum[blo1][a[i]]); if(num >= ma) { if(num > ma) { ma = num; ma_col = a[i]; } else { ma_col = min(ma_col,a[i]); } } } for(int i = R;i > (blo2 - 1) * blo;i --) { int num = cnt[a[i]]; if(tag) num += (sum[blo2 - 1][a[i]] - sum[blo1][a[i]]); if(num >= ma) { if(num > ma) { ma = num; ma_col = a[i]; } else { ma_col = min(ma_col,a[i]); } } } printf("%d\n",y[ma_col]); las = y[ma_col]; } } } int main( ) { Init( ); Solve( ); }