前言:
先說句閑話,分塊這個東西其實在第二次集訓剛剛開始的時候就拉着lc學過一陣,原因是在luogu上見到了某著名毒瘤出的末日時系列的一套題目,貌似大部分都是分塊,於是我想嘗試着去做幾道(畢竟是個珂學家),但是看完題目就自閉了(noip毒瘤果不虛傳),這兩天學長又給我們講了一些分塊的知識,就把loj上的幾道入門題再撿起來說一下吧。
入門基礎知識就不說什么了,學長講過了,藍皮書上面也有。
這里前面和后面的代碼風格可能不太一樣,8之前的都是在學長講課之前寫的,9照學長代碼修改了一些地方。
數列分塊入門 1
基礎的操作,之前學過的線段樹樹狀數組也都可以很好的解決,如果不是為了刻意練習分塊的話以后見到建議樹狀數組(逃)

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e6 + 10; 4 int block, a[N], add[N], belong[N], sum[N], siz[N]; 5 void change(int l, int r, int num) { 6 for (int i = l; i <= min(r, belong[l] * block); ++i) { 7 a[i] += num; 8 sum[belong[i]] += num; 9 } 10 if (belong[l] == belong[r]) 11 return; 12 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) { 13 a[i] += num; 14 sum[belong[i]] += num; 15 } 16 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) { 17 add[i] += num; 18 } 19 } 20 int main() { 21 int n; 22 scanf("%d", &n); 23 for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); 24 block = (int)sqrt(n); 25 for (int i = 1; i <= n; ++i) { 26 belong[i] = (i - 1) / block + 1; 27 siz[belong[i]]++; 28 sum[belong[i]] += a[i]; 29 } 30 for (int i = 1; i <= n; ++i) { 31 int t, x, y, z; 32 scanf("%d%d%d%d", &t, &x, &y, &z); 33 if (t == 0) { 34 change(x, y, z); 35 } else { 36 printf("%d\n", a[y] + add[belong[y]]); 37 } 38 } 39 return 0; 40 }
數列分塊入門 2
這道題貌似和學長講課的例題很像很像......其實就是一個查詢區間內某個元素的排名,對於每個塊開一個vector,將每一個vector內的元素進行排序,在查找的時候不足一塊的暴力枚舉統計答案,整塊內的元素直接二分查找位置統計答案,修改的時候由於整塊加一個數字不影響相對大小,於是vector內元素順序不變,打一個lazy即可,邊角的話由於元素大小關系變化,需要暴力把塊內數據重新再放一次vector再排序,由於塊長只有sqrt(n),也可以很好的跑過去。

1 #include <bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int N = 1e6 + 10; 5 int n, block, a[N], add[N], belong[N], sum[N]; 6 vector<int> ve[N]; 7 void reset(int id) { 8 ve[id].clear(); 9 for (int i = (id - 1) * block + 1; i <= min(n, id * block); ++i) ve[id].push_back(a[i]); 10 sort(ve[id].begin(), ve[id].end()); 11 } 12 void change(int l, int r, int num) { 13 for (int i = l; i <= min(r, belong[l] * block); ++i) { 14 a[i] += num; 15 sum[belong[i]] += num; 16 } 17 reset(belong[l]); 18 if (belong[l] == belong[r]) 19 return; 20 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) { 21 a[i] += num; 22 sum[belong[i]] += num; 23 } 24 reset(belong[r]); 25 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) add[i] += num; 26 } 27 int query(int l, int r, int num) { 28 int ans = 0; 29 for (int i = l; i <= min(r, belong[l] * block); ++i) { 30 if (a[i] + add[belong[i]] < num) 31 ans++; 32 } 33 if (belong[l] == belong[r]) 34 return ans; 35 for (int i = (belong[r] - 1) * block + 1; i <= r; ++i) { 36 if (a[i] + add[belong[i]] < num) 37 ans++; 38 } 39 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) { 40 ans += lower_bound(ve[i].begin(), ve[i].end(), num - add[i]) - ve[i].begin(); 41 } 42 return ans; 43 } 44 signed main() { 45 scanf("%lld", &n); 46 block = (int)sqrt(n); 47 for (int i = 1; i <= n; ++i) { 48 scanf("%lld", &a[i]); 49 belong[i] = (i - 1) / block + 1; 50 sum[belong[i]] += a[i]; 51 ve[belong[i]].push_back(a[i]); 52 } 53 for (int i = 1; i <= belong[n]; ++i) { 54 sort(ve[i].begin(), ve[i].end()); 55 } 56 for (int i = 1; i <= n; ++i) { 57 int t, x, y, z; 58 scanf("%lld%lld%lld%lld", &t, &x, &y, &z); 59 if (t == 0) { 60 change(x, y, z); 61 } else { 62 printf("%lld\n", query(x, y, z * z)); 63 } 64 } 65 return 0; 66 }
數列分塊入門 3
開vector,二分查找,整塊打lazy,邊角暴力重建,具體思路同2,貌似比2要簡單一些。

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e6 + 10; 4 int n, block, a[N], add[N], belong[N]; 5 vector<int> ve[N]; 6 void reset(int id) { 7 ve[id].clear(); 8 for (int i = (id - 1) * block + 1; i <= min(n, id * block); ++i) ve[id].push_back(a[i]); 9 sort(ve[id].begin(), ve[id].end()); 10 } 11 void change(int l, int r, int num) { 12 for (int i = l; i <= min(belong[l] * block, r); ++i) a[i] += num; 13 reset(belong[l]); 14 if (belong[l] == belong[r]) 15 return; 16 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) a[i] += num; 17 reset(belong[r]); 18 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) add[i] += num; 19 } 20 int query(int l, int r, int num) { 21 int ans = -1; 22 for (int i = l; i <= min(r, belong[l] * block); ++i) 23 if (a[i] + add[belong[l]] < num) 24 ans = max(ans, a[i] + add[belong[l]]); 25 if (belong[l] == belong[r]) 26 return ans; 27 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) 28 if (a[i] + add[belong[r]] < num) 29 ans = max(ans, a[i] + add[belong[r]]); 30 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) { 31 int pos = lower_bound(ve[i].begin(), ve[i].end(), num - add[i]) - ve[i].begin(); 32 if (pos) 33 ans = max(ans, ve[i][pos - 1] + add[i]); 34 } 35 return ans; 36 } 37 int main() { 38 scanf("%d", &n); 39 block = (int)sqrt(n); 40 for (int i = 1; i <= n; ++i) { 41 belong[i] = (i - 1) / block + 1; 42 scanf("%d", &a[i]); 43 ve[belong[i]].push_back(a[i]); 44 } 45 for (int i = 1; i <= belong[n]; ++i) sort(ve[i].begin(), ve[i].end()); 46 for (int i = 1; i <= n; ++i) { 47 int t, x, y, z; 48 scanf("%d%d%d%d", &t, &x, &y, &z); 49 if (t == 0) { 50 change(x, y, z); 51 } else { 52 printf("%d\n", query(x, y, z)); 53 } 54 } 55 return 0; 56 }
數列分塊入門 4
線段樹和樹狀數組基本操作,分塊也可搞,不太清楚問什么要放在第4個的位置(也許不按難度排序?),以后見到建議樹狀數組。

1 #include <bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 const int N = 1e6 + 10; 5 int n, block, a[N], siz[N], sum[N], add[N], belong[N], Mod; 6 void change(int l, int r, int num) { 7 for (int i = l; i <= min(r, belong[l] * block); ++i) { 8 a[i] += num; 9 sum[belong[i]] += num; 10 } 11 if (belong[l] == belong[r]) 12 return; 13 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) { 14 a[i] += num; 15 sum[belong[i]] += num; 16 } 17 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) add[i] += num; 18 } 19 int query(int l, int r) { 20 int ans = 0; 21 for (int i = l; i <= min(r, belong[l] * block); ++i) ans = (ans + a[i] + add[belong[i]]) % Mod; 22 if (belong[l] == belong[r]) 23 return ans; 24 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) ans = (ans + a[i] + add[belong[i]]) % Mod; 25 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) ans = (ans + sum[i] + add[i] * siz[i]) % Mod; 26 return ans; 27 } 28 signed main() { 29 scanf("%lld", &n); 30 block = (int)sqrt(n); 31 for (int i = 1; i <= n; ++i) { 32 belong[i] = (i - 1) / block + 1; 33 scanf("%lld", &a[i]); 34 sum[belong[i]] += a[i]; 35 siz[belong[i]]++; 36 } 37 for (int i = 1; i <= n; ++i) { 38 int t, x, y, z; 39 scanf("%lld%lld%lld%lld", &t, &x, &y, &z); 40 if (t == 0) { 41 change(x, y, z); 42 } else { 43 Mod = z + 1; 44 printf("%lld\n", query(x, y)); 45 } 46 } 47 return 0; 48 }
數列分塊入門 5
如果csm學長講花式線段樹的那節課認真聽的話應該會用勢能分析來做這道題,分塊做法雖然沒有那么復雜,但是借鑒了其思路,一個塊內的元素如果都是1或0的話就不用再對其進行開根操作了,反正值也不變,如果不是的話就暴力對每一個數字進行開根,雖然聽上去會T,但是真的跑的挺快的,畢竟一個數字開不了幾次根就成1了,做完后可以去 luoguP4145 那里水一個經驗~

1 #include <bits/stdc++.h> 2 #define debug puts("-debug-") 3 #define int long long 4 using namespace std; 5 const int N = 1e6 + 10; 6 int block, a[N], sum[N], siz[N], belong[N], jump[N]; 7 void change(int id) { 8 sum[id] = 0; 9 bool flag = 1; 10 for (int i = (id - 1) * block + 1; i <= block * id; ++i) { 11 a[i] = sqrt(a[i]); 12 sum[id] += a[i]; 13 if (a[i] != 1 && a[i] != 0) 14 flag = 0; 15 } 16 jump[id] = flag; 17 } 18 void Sqrt(int l, int r) { 19 for (int i = l; i <= min(r, belong[l] * block); ++i) { 20 sum[belong[i]] -= a[i]; 21 a[i] = sqrt(a[i]); 22 sum[belong[i]] += a[i]; 23 } 24 if (belong[l] == belong[r]) 25 return; 26 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) { 27 sum[belong[i]] -= a[i]; 28 a[i] = sqrt(a[i]); 29 sum[belong[i]] += a[i]; 30 } 31 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) { 32 if (jump[i]) 33 continue; 34 change(i); 35 } 36 } 37 int query(int l, int r) { 38 int ans = 0; 39 for (int i = l; i <= min(r, belong[l] * block); ++i) ans += a[i]; 40 if (belong[l] == belong[r]) 41 return ans; 42 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) ans += a[i]; 43 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) ans += sum[i]; 44 return ans; 45 } 46 signed main() { 47 int n; 48 scanf("%lld", &n); 49 block = sqrt(n); 50 for (int i = 1; i <= n; ++i) { 51 belong[i] = (i - 1) / block + 1; 52 scanf("%lld", &a[i]); 53 sum[belong[i]] += a[i]; 54 siz[belong[i]]++; 55 } 56 for (int i = 1; i <= n; ++i) { 57 int t, x, y, z; 58 scanf("%lld%lld%lld%lld", &t, &x, &y, &z); 59 if (t == 0) { 60 Sqrt(x, y); 61 } else 62 printf("%lld\n", query(x, y)); 63 } 64 return 0; 65 }
數列分塊入門 6
(看到數據隨機生成就想寫珂朵莉樹還有救嗎)
這道題如果數據范圍小的話可以直接用vector自帶的insert操作水過這道題,但是1e5的數據,期望n^2還是算了......
這道題雖然我們不直接用insert但是可以借助vector進行操作,對於每個塊開一個vector,每次對於插入位置直接暴力查找在那個塊里面,之后暴力插入就可以了,因為塊的大小是sqrt(n),所以插入的時間復雜度是可以接受的,最好在發現某一個塊的大小和其他塊極其不平衡的時候可以考慮重新分塊,但是這道題出題人比較懶,數據隨機,所以不重分也可以過掉。

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e6 + 10; 4 int n, block, a[N], siz[N], belong[N]; 5 vector<int> ve[N]; 6 void Insert(int pos, int num) { 7 int now = 1; 8 while (pos > ve[now].size()) { 9 pos -= ve[now].size(); 10 now++; 11 } 12 ve[now].insert(ve[now].begin() + pos, num); 13 } 14 int query(int pos) { 15 int now = 1; 16 while (pos > ve[now].size()) { 17 pos -= ve[now].size(); 18 now++; 19 } 20 return ve[now][pos - 1]; 21 } 22 int main() { 23 scanf("%d", &n); 24 block = sqrt(n); 25 for (int i = 1; i <= n; ++i) { 26 belong[i] = (i - 1) / block + 1; 27 scanf("%d", &a[i]); 28 siz[belong[i]]++; 29 ve[belong[i]].push_back(a[i]); 30 } 31 for (int i = 1; i <= n; ++i) { 32 int t, x, y, z; 33 scanf("%d%d%d%d", &t, &x, &y, &z); 34 if (t == 0) { 35 Insert(x - 1, y); 36 } else { 37 printf("%d\n", query(y)); 38 } 39 } 40 return 0; 41 }
數列分塊入門 7
和luogu上某道線段樹的板子題基本一樣,分塊做法和線段樹也有不少相似之處,處理好lazy標記,注意先乘再加的先后順序就可以了,如果線段樹學的好的話這道題用分塊寫一定不成問題,(然而juruo當時調了一陣時間,以后見到強烈建議線段樹QAQ,分塊還是用不熟)

1 #include <bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int N = 1e6 + 10; 5 const int Mod = 10007; 6 int n, block, sum[N], a[N], add[N], mul[N], belong[N]; 7 void pushdown(int id) { 8 for (int i = (id - 1) * block + 1; i <= id * block; ++i) { 9 a[i] = (a[i] * mul[belong[i]] % Mod + add[belong[i]]) % Mod; 10 } 11 add[id] = 0; 12 mul[id] = 1; 13 } 14 void Add(int l, int r, int num) { 15 pushdown(belong[l]); 16 for (int i = l; i <= min(r, belong[l] * block); ++i) { 17 a[i] = (a[i] + num) % Mod; 18 } 19 if (belong[l] == belong[r]) 20 return; 21 pushdown(belong[r]); 22 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) { 23 a[i] = (a[i] + num) % Mod; 24 } 25 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) { 26 add[i] = (add[i] + num) % Mod; 27 } 28 } 29 void mult(int l, int r, int num) { 30 pushdown(belong[l]); 31 for (int i = l; i <= min(r, belong[l] * block); ++i) { 32 a[i] = (a[i] * num) % Mod; 33 } 34 if (belong[l] == belong[r]) 35 return; 36 pushdown(belong[r]); 37 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) { 38 a[i] = (a[i] * num) % Mod; 39 } 40 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) { 41 add[i] = (add[i] * num) % Mod; 42 mul[i] = (mul[i] * num) % Mod; 43 } 44 } 45 int query(int pos) { return (a[pos] * mul[belong[pos]] % Mod + add[belong[pos]]) % Mod; } 46 signed main() { 47 scanf("%lld", &n); 48 block = sqrt(n); 49 for (int i = 1; i <= n; ++i) { 50 belong[i] = (i - 1) / block + 1; 51 scanf("%lld", &a[i]); 52 mul[belong[i]] = 1; 53 } 54 for (int i = 1; i <= n; ++i) { 55 int t, x, y, z; 56 scanf("%lld%lld%lld%lld", &t, &x, &y, &z); 57 if (t == 0) { 58 Add(x, y, z); 59 } else if (t == 1) { 60 mult(x, y, z); 61 } else { 62 printf("%lld\n", query(y)); 63 } 64 } 65 return 0; 66 }
數列分塊入門 8
基本思路和前面的一樣,大塊直接lazy,小塊暴力處理,這道題的lazy我們可以表示為當前塊是否已經都被賦了值,如果賦的值一樣的話就可以避免一次操作,不然修改lazy,邊角詢問之前要把所在的塊整個重新賦一次值,當然是在有lazy的時候。

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e6 + 10; 4 int n, block, a[N], update[N], belong[N], siz[N]; 5 void reset(int id) { 6 if (update[id] == -1) 7 return; 8 for (int i = (id - 1) * block + 1; i <= id * block; ++i) a[i] = update[id]; 9 update[id] = -1; 10 } 11 int query(int l, int r, int num) { 12 int ans = 0; 13 reset(belong[l]); 14 for (int i = l; i <= min(r, belong[l] * block); ++i) { 15 if (a[i] == num) 16 ans++; 17 a[i] = num; 18 } 19 if (belong[l] == belong[r]) 20 return ans; 21 reset(belong[r]); 22 for (int i = r; i >= (belong[r] - 1) * block + 1; --i) { 23 if (a[i] == num) 24 ans++; 25 a[i] = num; 26 } 27 for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) { 28 if (update[i] != -1) { 29 if (update[i] == num) 30 ans += siz[i]; 31 else 32 update[i] = num; 33 } else { 34 for (int j = (i - 1) * block + 1; j <= i * block; ++j) { 35 if (a[j] == num) 36 ans++; 37 a[j] = num; 38 } 39 update[i] = num; 40 } 41 } 42 return ans; 43 } 44 int main() { 45 scanf("%d", &n); 46 block = sqrt(n); 47 memset(update, -1, sizeof(update)); 48 for (int i = 1; i <= n; ++i) { 49 belong[i] = (i - 1) / block + 1; 50 scanf("%d", &a[i]); 51 siz[belong[i]]++; 52 } 53 for (int i = 1; i <= n; ++i) { 54 int x, y, z; 55 scanf("%d%d%d", &x, &y, &z); 56 printf("%d\n", query(x, y, z)); 57 } 58 return 0; 59 }
數列分塊入門 9
分塊經典的區間眾數問題,原題好像是BZOJ上一道叫做“蒲公英”的題目(但是BZOJ好像已經上不去了),線段樹和樹狀數組此時就不能解決問題了。我們還是把處理的區間分為中間整塊和兩邊分散兩種情況,我們最終的眾數一定是中間整塊的眾數或者是兩邊的某個數,於是對於每個塊的分界的地方我們都可以處理出之間的眾數,我們在處理詢問的時候就可以把兩邊的數字和中間的眾數分別計算一次,統計一下答案就行了,juruo的代碼死活過不去,只有80pts,lc大佬好像說這題的塊長u要設成30?不然會T掉。

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <map> 6 #include <vector> 7 #include <cmath> 8 using namespace std; 9 const int maxn = 1e5 + 5; 10 int f[4000][4005]; 11 inline int read() { 12 int x = 0, f = 1; 13 char ch = getchar(); 14 while (ch < '0' || ch > '9') { 15 if (ch == '-') 16 f = -1; 17 ch = getchar(); 18 } 19 while (ch >= '0' && ch <= '9') { 20 x = (x << 1) + (x << 3) + (ch ^ 48); 21 ch = getchar(); 22 } 23 return x * f; 24 } 25 int a[maxn], shuyu[maxn], cntt, val[maxn], blo, n, cnt[maxn]; 26 map<int, int> mp; 27 vector<int> g[maxn]; 28 void solve(int id) { 29 memset(cnt, 0, sizeof(cnt)); 30 int mmax = 0, ans = 0; 31 for (int i = (id - 1) * blo + 1; i <= n; i++) { 32 cnt[a[i]]++; 33 int p = shuyu[i]; 34 if (cnt[a[i]] > mmax || (cnt[a[i]] == mmax && val[ans] > val[a[i]])) { 35 mmax = cnt[a[i]]; 36 ans = a[i]; 37 } 38 f[id][p] = ans; 39 } 40 } 41 int cxx(int l, int r, int val) { 42 return upper_bound(g[val].begin(), g[val].end(), r) - lower_bound(g[val].begin(), g[val].end(), l); 43 } 44 int cx(int l, int r) { 45 int mmax = 0, ans = 0; 46 for (int i = l; i <= min(r, shuyu[l] * blo); i++) { 47 int now = cxx(l, r, a[i]); 48 if (now > mmax || (now == mmax && val[ans] > val[a[i]])) { 49 mmax = now; 50 ans = a[i]; 51 } 52 } 53 if (shuyu[l] == shuyu[r]) 54 return ans; 55 for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { 56 int now = cxx(l, r, a[i]); 57 if (now > mmax || (now == mmax && val[ans] > val[a[i]])) { 58 mmax = now; 59 ans = a[i]; 60 } 61 } 62 int noww = f[shuyu[l] + 1][shuyu[r] - 1]; 63 int kk = cxx(l, r, noww); 64 if (kk > mmax || (kk == mmax && val[ans] > val[noww])) { 65 mmax = kk; 66 ans = noww; 67 } 68 return ans; 69 } 70 int main() { 71 n = read(); 72 blo = 30; 73 for (int i = 1; i <= n; i++) { 74 shuyu[i] = (i - 1) / blo + 1; 75 a[i] = read(); 76 if (!mp[a[i]]) { 77 mp[a[i]] = ++cntt; 78 val[cntt] = a[i]; 79 } 80 a[i] = mp[a[i]]; 81 g[a[i]].push_back(i); 82 } 83 for (int i = 1; i <= shuyu[n]; i++) { 84 solve(i); 85 } 86 for (int i = 1; i <= n; i++) { 87 int l = read(), r = read(); 88 if (l > r) 89 swap(l, r); 90 printf("%d\n", val[cx(l, r)]); 91 } 92 return 0; 93 }

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 #include <map> 6 #include <cmath> 7 #define debug puts("-debug-") 8 const int N = 3e5 + 10; 9 const int maxn = 1e3 + 10; 10 std::vector<int> ve[N]; 11 std::vector<int> nu; 12 std::map<int, int> mp; 13 std::map<int, bool> vis; 14 int a[N], b[N], n, belong[N], block, num[maxn][maxn], L[N], R[N], tim[N], tot; 15 int Max, res; 16 void solve(int id) { 17 mp.clear(); 18 int mmax = 0, ans = 0; 19 for (int i = L[id]; i <= n; i++) { 20 mp[a[i]]++; 21 int p = belong[i]; 22 if (mp[a[i]] > mmax || (mp[a[i]] == mmax && a[i] < ans)) { 23 mmax = mp[a[i]]; 24 ans = a[i]; 25 } 26 num[id][p] = ans; 27 } 28 } 29 void query(int l, int r) { 30 nu.clear(); 31 vis.clear(); 32 for (int i = l; i <= std::min(R[belong[l]], r); ++i) { 33 if (vis[a[i]]) 34 continue; 35 nu.push_back(a[i]); 36 vis[a[i]] = 1; 37 } 38 if (belong[l] != belong[r]) { 39 for (int i = L[belong[r]]; i <= r; ++i) { 40 if (vis[a[i]]) 41 continue; 42 nu.push_back(a[i]); 43 vis[a[i]] = 1; 44 } 45 } 46 if (!vis[num[belong[l] + 1][belong[r] - 1]] && belong[l] + 1 <= belong[r] - 1) 47 nu.push_back(num[belong[l] + 1][belong[r] - 1]); 48 std::sort(nu.begin(), nu.end()); 49 for (int i = 0; i < nu.size(); ++i) { 50 int now = std::lower_bound(b + 1, b + tot + 1, nu[i]) - b; 51 int p1 = std::lower_bound(ve[now].begin(), ve[now].end(), l) - ve[now].begin(); 52 int p2 = std::lower_bound(ve[now].begin(), ve[now].end(), r) - ve[now].begin(); 53 if (ve[now][p1] > r) 54 continue; 55 while (ve[now][p2] > r) p2--; 56 if (p2 < p1) 57 continue; 58 int len = p2 - p1 + 1; 59 if (Max < len) { 60 Max = len; 61 res = now; 62 } 63 } 64 } 65 signed main() { 66 scanf("%d", &n); 67 block = sqrt(n); 68 for (int i = 1; i <= n; ++i) { 69 scanf("%d", &a[i]); 70 b[i] = a[i]; 71 belong[i] = (i - 1) / block + 1; 72 if (!L[belong[i]]) 73 L[belong[i]] = i; 74 R[belong[i]] = i; 75 } 76 std::sort(b + 1, b + n + 1); 77 tot = std::unique(b + 1, b + n + 1) - b - 1; 78 for (int i = 1; i <= n; ++i) { 79 int pos = std::lower_bound(b + 1, b + tot + 1, a[i]) - b; 80 ve[pos].push_back(i); 81 } 82 for (int i = 1; i <= belong[n]; ++i) solve(i); 83 for (int i = 1; i <= n; ++i) { 84 int l, r; 85 scanf("%d%d", &l, &r); 86 Max = 0; 87 query(l, r); 88 printf("%d\n", b[res]); 89 } 90 return 0; 91 }
后記
做完了為什么感覺這些題目的處理方法一個比一個暴力