【bzoj2724】蒲公英(分块)
题目分析
付费题哈哈。题意就是求区间众数,由于区间众数无法快速合并,所以不能使用传统的数据结构如线段树等。
这时分块就能派上很大的用场。将序列分成$\sqrt{n}+$块,每块大小$\sqrt{n}+$,通过预处理得到cnt[i][j], ans[i][j]分别表示i在前j块中出现的次数,和第i块到第j块的众数是多少。
那么查询时我们就得到了至多$\sqrt{n}$个连续的块,和至多$2\sqrt{n}$个零散的元素,对于零散的元素,暴力,对于连续的块,直接使用预处理。
code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<algorithm> using namespace std; const int N = 4e4 + 5, oo = 0x7fffffff; int n, m, S; int val[N], num[N], len; int blk[N], bl[300], br[300], blkCnt, sum[N]; int ans[300][300], cnt[N][300]; int read(){ int i=0,f=1;char ch; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') {f=-1;ch=getchar();} for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+(ch^48); return f*i; } inline void wr(int x){ if(x < 0) putchar('-'), x = -x; if(x > 9) wr(x / 10); putchar(x % 10 + '0'); } inline void disc_init(){ sort(num + 1, num + len + 1); len = unique(num + 1, num + len + 1) - (num + 1); for(int i = 1; i <= n; i++) val[i] = lower_bound(num + 1, num + len + 1, val[i]) - num; // for(int i = 1; i <= n; i++) cout<<val[i]<<endl; } inline void initBlk(){ blk[1] = 1, bl[blkCnt = 1] = 1, cnt[val[1]][1] = 1; for(int i = 2; i <= n; i++){ if(i % S == 0){ br[blkCnt] = i; blk[i] = blkCnt; cnt[val[i]][blkCnt]++; if(i + 1 <= n) bl[++blkCnt] = i + 1; continue; } blk[i] = blkCnt; cnt[val[i]][blkCnt]++; } br[blkCnt] = n; } inline void initData(){ for(int i = 1; i <= len; i++) for(int j = 2; j <= blkCnt; j++) cnt[i][j] += cnt[i][j - 1]; for(int i = 1; i <= blkCnt; i++){ int maxx = -oo, cur = oo, sum[N] = {0}; for(int j = i; j <= blkCnt; j++){ for(int k = bl[j]; k <= br[j]; k++){ int ret = ++sum[val[k]]; if(ret > maxx) maxx = ret, cur = val[k]; else if(ret == maxx && val[k] < cur) cur = val[k]; } ans[i][j] = cur; } } } inline int query(int l, int r){ if(l > r) swap(l, r); int blk_L = blk[l] + 1, blk_R = blk[r] - 1; if(bl[blk_L - 1] == l) blk_L--; if(br[blk_R + 1] == r) blk_R++; if(blk_L > blk_R){ int sum[N] = {0}, maxx = -oo, ret = oo; for(int i = l; i <= r; i++){ int c = ++sum[val[i]]; if(c > maxx) maxx = c, ret = val[i]; else if(c == maxx && val[i] < ret) ret = val[i]; } return ret; } int ret = ans[blk_L][blk_R], sum[N] = {0}, ret_cnt = cnt[ret][blk_R] - cnt[ret][blk_L - 1]; for(int i = l; i < bl[blk_L]; i++){ int c; if(sum[val[i]]) c = ++sum[val[i]]; else{ sum[val[i]] = cnt[val[i]][blk_R] - cnt[val[i]][blk_L - 1]; c = ++sum[val[i]]; } if(c > ret_cnt) ret = val[i], ret_cnt = c; else if(c == ret_cnt && val[i] < ret) ret = val[i]; } for(int i = br[blk_R] + 1; i <= r; i++){ int c; if(sum[val[i]]) c = ++sum[val[i]]; else{ sum[val[i]] = cnt[val[i]][blk_R] - cnt[val[i]][blk_L - 1]; c = ++sum[val[i]]; } if(c > ret_cnt) ret = val[i], ret_cnt = c; else if(c == ret_cnt && val[i] < ret) ret = val[i]; } return ret; } int main(){ //freopen("h.in","r",stdin); n = read(), m = read(); S = 400; for(int i = 1; i <= n; i++) val[i] = num[++len] = read(); disc_init(); initBlk(); initData(); int ans = 0; for(int i = 1; i <= m; i++){ int l = read(), r = read(); l = (l + ans - 1) % n + 1, r = (r + ans - 1) % n + 1; wr(ans = num[query(l, r)]), putchar('\n'); } return 0; }