時隔多日,終於又想起來要寫題解了啊 !!!html
分塊的基本知識和概念都在(一)中講過了,那麼咱們今天就來看一些稍微有點難度的題目吧。前端
若是有什麼要補充的我就穿插在題目裏面講了。ios
基本上,大多數的分塊的題目使用樹狀數組或者線段樹都是能夠作的,甚至更快更優秀git
可是實際上分塊存在的意義並非爲了服務於咱們的懶惰,他是有必定的特殊意義的。算法
那麼咱們來思考一個問題:後端
如今有一個序列,給出幾個詢問,求問某段區間內的最大值。數組
對於這個問題,線段樹能夠作嗎?固然能夠,可是超級麻煩。優化
這個時候就是咱們分塊做用體現最大的時候了。spa
分塊成爲最優解-->不知足區間可加性的序列詢問問題code
雖然比這道 [Violet]蒲公英 要簡單的題仍是有的,可是這道畢竟比較典型嘛。
題目背景
親愛的哥哥:
你在那個城市裏面過得好嗎?
我在家裏面最近很開心呢。昨天晚上奶奶給我講了那個叫「絕望」的大壞蛋的故事的說!它把人們的房子和田地搞壞,還有好多小朋友也被它殺掉了。我以爲把那麼可怕的怪物召喚出來的那個壞蛋也很壞呢。不過奶奶說他是很難受的時候才作出這樣的事的……
最近村子裏長出了一大片一大片的蒲公英。一颳風,這些蒲公英就能飄到好遠的地方了呢。我以爲要是它們能飄到那個城市裏面,讓哥哥看看就行了呢!
哥哥你要快點回來哦!
愛你的妹妹 Violet
Azure 讀完這封信以後微笑了一下。
「蒲公英嗎……」
題目描述
在鄉下的小路旁種着許多蒲公英,而咱們的問題正是與這些蒲公英有關。
爲了簡化起見,咱們把全部的蒲公英當作一個長度爲n的序列 (a_1,a_2..a_n)(a1,a2..an),其中 a_iai 爲一個正整數,表示第i棵蒲公英的種類編號。
而每次詢問一個區間 [l,r],你須要回答區間裏出現次數最多的是哪一種蒲公英,若是有若干種蒲公英出現次數相同,則輸出種類編號最小的那個。
注意,你的算法必須是在線的
輸入輸出格式
輸入格式:
第一行兩個整數 n,m ,表示有n株蒲公英,m 次詢問。
接下來一行n個空格分隔的整數 a_iai ,表示蒲公英的種類
再接下來m 行每行兩個整數 l_0,r_0l0,r0,咱們令上次詢問的結果爲 x(若是這是第一次詢問, 則 x=0)。
令 l=(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 行。每行一個整數,表示每次詢問的結果。
輸入輸出樣例
輸入樣例#1:6 3 1 2 3 2 1 2 1 5 3 6 1 5輸出樣例#1:
1 2 1
強制在線啊,區間最大值啊。
是很完美的卡掉莫隊和線段樹的題面啊。
那麼咱們選擇採用分塊作法。
首先將區間L~R分紅三段,分開處理。
1.整塊 l ~ r 。
2.前端不滿。
3.後端不滿。
那麼,很顯然 --> maxn = max { cnt[ 2. /3. ] , maxn[ l ~ r ] };
如今咱們須要考慮的就是如何暴力處理以最小代價了。
以前一直都沒介紹怎麼計算塊的大小,那就這道題補上吧。
計算塊的大小主要就是根據時間複雜度,防止一不當心就 T 了之類的。
那麼就用事實說明吧(感受更有說服力一點)
若是有錯誤必定要告訴我~
另外這題還能水過!!!luogu AC大法
離散化+暴力處理區間衆數 + luogu氧氣優化!!
O2真好~~~我愛!!
由於我比較菜因此解法二的代碼不是個人~~我也不知道是誰的 /無奈
解法一
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int MA=40001; const int u=41; int c[u][u][MA],f[u][u],d[u][u]; int a[MA],b[MA],fa[MA],fb[MA]; int st[u],ed[u]; int n,m,t,l,tot; int x,y,ans,L,R,cnt,num; void pw() { t=(int)pow(n*1.0,1.0/3); if(t) l=n/t; for(int i=1;i<=t;i++) { st[i]=(i-1)*l+1; ed[i]=i*l; } if(ed[t]<n) { st[t+1]=ed[t]+1; ed[++t]=n; } memcpy(fa,a,sizeof(a)); sort(fa+1,fa+n+1); for(int i=1;i<=n;i++) if(i==1||fa[i]!=fa[i-1]) fb[++tot]=fa[i]; for(int i=1;i<=n;i++) b[i]=lower_bound(fb+1,fb+tot+1,a[i])-fb; for(int i=1;i<=t;i++) for(int j=i;j<=t;j++) { for(int k=st[i];k<=ed[j];k++) c[i][j][b[k]]++; for(int k=1;k<=tot;k++) if(c[i][j][k]>f[i][j]||c[i][j][k]==f[i][j]&&k<d[i][j]) { f[i][j]=c[i][j][k]; d[i][j]=k; } } return; } inline void upd(int i) { c[L][R][b[i]]++; if(c[L][R][b[i]]>cnt||c[L][R][b[i]]==cnt&&b[i]<num) { cnt=c[L][R][b[i]]; num=b[i]; } } int solve(int x,int y) { int r; if(x>y) swap(x,y); for(int i=1;i<=t;i++) if(x<=ed[i]) { l=i; break; } for(int i=t;i;i--) if(y>=st[i]) { r=i; break; } if(l+1<=r-1) { L=l+1; R=r-1; } else L=R=0; cnt=f[L][R]; num=d[L][R]; if(l==r) { for(int i=x;i<=y;i++) upd(i); for(int i=x;i<=y;i++) c[L][R][b[i]]--; } else { for(int i=x;i<=ed[l];i++) upd(i); for(int i=st[r];i<=y;i++) upd(i); for(int i=x;i<=ed[l];i++) c[L][R][b[i]]--; for(int i=st[r];i<=y;i++) c[L][R][b[i]]--; } return fb[num]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); pw(); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); ans=solve((x+ans-1)%n+1,(y+ans-1)%n+1); printf("%d\n",ans); } return 0; }
解法二:
#define FILEIO #define INPUT "dandelion.in" #define OUTPUT "dandelion.out" #include <set> #include <map> #include <cstdio> #include <cstring> #include <algorithm> #include <cctype> #include <vector> #include <cassert> #include <cmath> #define mp make_pair #define pb push_back #define foreach(i,T) for(__typeof(T.begin()) i = T.begin(); i != T.end(); ++i) using namespace std; namespace Solve { const int MAXN = 40013; const int MAXM = 36; inline int ScanInt(void) { int r = 0, c, d; while (!isdigit(c = getchar()) && c != '-'); if (c != '-') r = c - '0'; d = c; while ( isdigit(c = getchar())) r = r * 10 + c - '0'; return d=='-'?-r:r; } int n, m, a[MAXN], cnt = 0, p, belong[MAXN], t, fim[MAXN]; set<int> S; map<int, int> M; inline void Input(void) { n = ScanInt(), m = ScanInt(), p = pow(n, 0.666666666666), t = n / p; if (n % p != 0) t++; for (int i = 1; i <= n; i++) S.insert(a[i] = ScanInt()); foreach(it, S) M[*it] = ++cnt; for (int i = 1; i <= n; i++) fim[M[a[i]]] = a[i], a[i] = M[a[i]]; } inline void Update(int t, int v, int &Max, int &pos) { if (v == Max && t < pos) pos = t; if (v > Max) pos = t, Max = v; } struct Node { int c[MAXN], pos, Max; inline void operator +=(const int t) { c[t]++; Update(t, c[t], Max, pos); } inline void operator -=(const int t) { c[t]--; } }f[MAXM][MAXM]; int C[MAXM][MAXN]; inline void Init(void) { for (int i = 1; i <= n; i++) { if ((i - 1) % p == 0) belong[i] = belong[i - 1] + 1; else belong[i] = belong[i - 1]; C[belong[i]][a[i]]++; } for (int i = 1; i <= t; i++) { for (int j = i; j <= t; j++) { for (int k = 1; k <= cnt; k++) f[i][j].c[k] = f[i][j - 1].c[k] + C[j][k]; for (int k = 1; k <= cnt; k++) Update(k, f[i][j].c[k], f[i][j].Max, f[i][j].pos); } } } int hash[MAXN]; inline int Cal(int l, int r) { int L = belong[l], R = belong[r]; if (L == R) { int Max = 0, pos = 0; for (int i = l; i <= r; i++) { hash[a[i]]++; Update(a[i], hash[a[i]], Max, pos); } for (int i = l; i <= r; i++) hash[a[i]]--; return fim[pos]; } if (belong[l] == belong[l - 1]) L++; if (belong[r] == belong[r + 1]) R--; int b = f[L][R].pos, u = f[L][R].Max; for (int i = l; belong[i] == belong[i - 1]; i++) f[L][R] += a[i]; for (int i = r; belong[i] == belong[i + 1]; i--) f[L][R] += a[i]; int ret = fim[f[L][R].pos]; for (int i = l; belong[i] == belong[i - 1]; i++) f[L][R] -= a[i]; for (int i = r; belong[i] == belong[i + 1]; i--) f[L][R] -= a[i]; f[L][R].pos = b, f[L][R].Max = u; return ret; } inline void solve(void) { Input(); Init(); int x = 0; for (int i = 1; i <= m; i++) { int l = ScanInt(), r = ScanInt(); l = (l + x - 1) % n + 1, r = (r + x - 1) % n + 1; if (l > r) swap(l, r); // fprintf(stderr, "%d %d\n", l, r); printf("%d\n", x = Cal(l, r)); } } } int main(void) { #ifdef FILEIO freopen(INPUT, "r", stdin); freopen(OUTPUT, "w", stdout); #endif Solve::solve(); return 0; }
解法三:
// luogu-judger-enable-o2 #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<vector> #include<map> #define itn int #define pos(x) (x+ans-1)%n+1 using namespace std; const int MA=50001; itn n,m,ans; int l,r; int a[MA],b[MA],ts[MA]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); int sum=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+sum+1,a[i])-b; while(m--) { scanf("%d%d",&l,&r); l=pos(l); r=pos(r); if(l>r) swap(l,r); for(itn i=l;i<=r;i++) ts[a[i]]++; int maxn=0,p=0; for(itn i=1;i<=sum;i++) { if(maxn<ts[i]){ maxn=ts[i]; p=i; } } cout<<b[p]<<endl; ans=b[p]; memset(ts,0,sizeof ts); } return 0; }
萬一我一不當心就寫掛了呢?
最後是類似題目的推薦!!題目均來源於luogu