1. 程式人生 > >【bzoj2724】蒲公英(分塊)

【bzoj2724】蒲公英(分塊)

sort 大小 int gin algorithm read oid n) 快速合並

題目分析

付費題哈哈。題意就是求區間眾數,由於區間眾數無法快速合並,所以不能使用傳統的數據結構如線段樹等。

這時分塊就能派上很大的用場。將序列分成$\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; }

【bzoj2724】蒲公英(分塊)