分块经典题竟然是一道黑题……
分块求区间众数的大体思想是对于询问区间[L, R],预处理出这中间的整块的众数,然后统计两边零散的数在[L, R]中出现的次数,最后取出现次数最多且最小的数。
因此需要一个sum[i][j]表示前 i 块中数字 j 出现的次数,ans[i][j]表示块 i 到 j 的众数。预处理sum用前缀和的思想,O(n√n)可完成。预处理ans就是枚举左端点是第几个块,然后每一次从这个块的左端点O(n)扫一遍,复杂度也是O(n√n)。
查询的时候,整块的众数即其个数分别是pos = ans[l + 1][r - 1],Max = sum[r - 1][pos] - sum[l][pos]。然后零散的数我们单独开一个数组记录一下,同时记录他在零三部分出现的次数num[i],这样这个数在[L, R]中出现的次数就是sum[r - 1][x] - sum[l][x] + num[x]。最后比较取大。
本题ai较大,所以要离散化,这并不影响众数。
采纳lba大佬的意见,为了避免重复运算从而降低常数,多开了三个数组分别记录每一个数属于哪个块,以及每一个块的左右端点是多少。

1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 4e4 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n, m, a[maxn], t[maxn]; 38 39 int S, Cnt = 0, blo[maxn], lb[210], rb[210]; 40 int sum[210][maxn], ans[210][210], num[maxn]; 41 void init() 42 { 43 S = sqrt(n); 44 Cnt = (n % S) ? n / S : n / S + 1; 45 for(int i = 1; i <= Cnt; ++i) lb[i] = (i - 1) * S, rb[i] = i * S - 1; 46 rb[Cnt] = n; //一定要有,否则会gg 47 for(int i = 1, j = 1; i <= n; ++i) blo[i] = j, j += (i == rb[j]); 48 for(int i = 1; i <= Cnt; ++i) 49 { 50 for(int j = 1; j <= n; ++j) sum[i][j] += sum[i - 1][j]; 51 for(int j = lb[i]; j <= rb[i]; ++j) sum[i][a[j]]++; 52 } 53 for(int i = 1; i <= Cnt; ++i) 54 { 55 Mem(num, 0); int Max = -1, pos; 56 for(int j = lb[i], k = i; j <= n; ++j) 57 { 58 if(++num[a[j]] > Max) Max = num[a[j]], pos = a[j]; 59 if(num[a[j]] == Max && a[j] < pos) pos = a[j]; 60 if(j == rb[k]) ans[i][k] = pos, k++; 61 } 62 } 63 } 64 int temp[210], cp = 0; 65 int query(int L, int R) 66 { 67 Mem(num, 0); cp = 0; 68 int l = blo[L], r = blo[R]; 69 int Max = -1, pos; 70 if(l == r) 71 { 72 for(int i = L; i <= R; ++i) 73 { 74 if(++num[a[i]] > Max) Max = num[a[i]], pos = a[i]; 75 if(num[a[i]] == Max && a[i] < pos) pos = a[i]; 76 } 77 return pos; 78 } 79 pos = ans[l + 1][r - 1]; Max = sum[r - 1][pos] - sum[l][pos]; 80 for(int i = L; i <= rb[l]; ++i) 81 { 82 if(!num[a[i]]) temp[++cp] = a[i]; 83 num[a[i]]++; 84 } 85 for(int i = lb[r]; i <= R; ++i) 86 { 87 if(!num[a[i]]) temp[++cp] = a[i]; 88 num[a[i]]++; 89 } 90 for(int i = 1; i <= cp; ++i) 91 { 92 int tp = sum[r - 1][temp[i]] - sum[l][temp[i]] + num[temp[i]]; 93 if(tp > Max) Max = tp, pos = temp[i]; 94 if(tp == Max && temp[i] < pos) pos = temp[i]; 95 } 96 return pos; 97 } 98 99 int Ans = 0; 100 101 int main() 102 { 103 n = read(); m = read(); 104 for(int i = 1; i <= n; ++i) t[i] = a[i] = read(); 105 sort(t + 1, t + n + 1); 106 int _n = unique(t + 1, t + n + 1) - t - 1; 107 for(int i = 1; i <= n; ++i) 108 a[i] = lower_bound(t + 1, t + _n + 1, a[i]) - t; 109 init(); 110 for(int i = 1; i <= m; ++i) 111 { 112 int L = read(), R = read(); 113 L = (L + Ans - 1) % n + 1; R = (R + Ans - 1) % n + 1; 114 if(L > R) swap(L, R); 115 Ans = t[query(L, R)]; //别忘了输出原数 116 write(Ans), enter; 117 } 118 return 0; 119 }