loj数列分块入门 1~9
前言:
先说句闲话,分块这个东西其实在第二次集训刚刚开始的时候就拉着lc学过一阵,原因是在luogu上见到了某著名毒瘤出的末日时系列的一套题目,貌似大部分都是分块,于是我想尝试着去做几道(毕竟是个珂学家),但是看完题目就自闭了(noip毒瘤果不虚传),这两天学长又给我们讲了一些分块的知识,就把loj上的几道入门题再捡起来说一下吧。
入门基础知识就不说什么了,学长讲过了,蓝皮书上面也有。
这里前面和后面的代码风格可能不太一样,8之前的都是在学长讲课之前写的,9照学长代码修改了一些地方。
数列分块入门 1
基础的操作,之前学过的线段树树状数组也都可以很好的解决,如果不是为了刻意练习分块的话以后见到建议树状数组(逃)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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),也可以很好的跑过去。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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要简单一些。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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个的位置(也许不按难度排序?),以后见到建议树状数组。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 那里水一个经验~
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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),所以插入的时间复杂度是可以接受的,最好在发现某一个块的大小和其他块极其不平衡的时候可以考虑重新分块,但是这道题出题人比较懒,数据随机,所以不重分也可以过掉。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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,分块还是用不熟)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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的时候。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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掉。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
后记
做完了为什么感觉这些题目的处理方法一个比一个暴力