题目链接https://loj.ac/problem/6285
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cstdio> 6 #include<string> 7 #include<vector> 8 #include<cmath> 9 #include<iomanip> 10 #include<bitset> 11 #include<queue> 12 #include<stack> 13 #include<map> 14 #include<set> 15 #include<list> 16 using namespace std; 17 const int maxn = 1e5 + 10; 18 int n, t, l, r, id, ans; 19 int pos[maxn], val[maxn], m[3500][3500], a[maxn], sum[maxn]; 20 map<int, int> ls; 21 vector<int> v[maxn]; 22 23 inline int read() 24 { 25 char ch = getchar(); int k = 0, f = 1; 26 while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} 27 while(ch >= '0' && ch <= '9') {k = (k << 1) + (k << 3) + ch - '0'; ch = getchar();} 28 return k * f; 29 } 30 31 inline int findy(int a, int l, int r) 32 { 33 return upper_bound(v[a].begin(), v[a].end(), r) - lower_bound(v[a].begin(), v[a].end(), l); // 第一个大于r的地址减去第一个大于等于l的地址可得区间内出现次数 34 } 35 36 inline void deal(int x) 37 { 38 int maxx = 0, mx = 0; 39 memset(sum, 0, sizeof(sum)); 40 for(int i = (x - 1) * t + 1; i <= n; ++i) 41 { 42 sum[a[i]]++; 43 if(sum[a[i]] > maxx || (sum[a[i]] == maxx) && val[mx] > val[a[i]]) 44 mx = a[i], maxx = sum[a[i]]; 45 m[x][pos[i]] = mx; // 记录第几块左边界到第几块右边界的最小众数 46 } 47 } 48 49 int query(int l,int r) 50 { 51 int cnt, mx=0, maxx; 52 mx = m[pos[l] + 1][pos[r] - 1]; 53 maxx = findy(mx, l, r); 54 55 if(pos[l]==pos[r]) 56 { 57 for(int i = l; i <= r; ++i) 58 { 59 cnt = findy(a[i], l, r); 60 if(cnt > maxx || ( cnt == maxx && val[mx] > val[a[i]])) mx = a[i], maxx = cnt; 61 } 62 } 63 64 else 65 { 66 for(int i = l; i <= pos[l]*t; ++i) 67 { 68 cnt = findy(a[i], l, r); 69 if(cnt > maxx || ( cnt == maxx && val[mx] > val[a[i]])) mx = a[i], maxx = cnt; 70 } 71 72 for(int i = (pos[r] - 1) * t + 1; i <= r; ++i) 73 { 74 cnt = findy(a[i], l, r); 75 if(cnt > maxx || (cnt == maxx && val[mx] > val[a[i]])) mx = a[i], maxx = cnt; 76 } 77 } 78 return mx; 79 } 80 81 int main() 82 { 83 n = read(); t = 100; // t取50 100 200 可以很好解决数据小但是分块多的情况不然可能会tle 84 85 for(int i = 1; i <= n; ++i) // 进行离散化 86 { 87 a[i] = read(); 88 if(!ls[a[i]]) 89 { 90 ls[a[i]] = ++id; // ls通过原值找现值 91 val[id] = a[i]; // val通过现值找原值 92 } 93 a[i] = ls[a[i]]; 94 v[a[i]].push_back(i); // 将相同值的序号存进vector,此时寻找某值在某区间内的次数就很好找 95 } 96 97 for(int i = 1; i <= n; ++i) pos[i] = (i - 1) / t + 1; 98 for(int i = 1; i <= pos[n]; ++i) deal(i); 99 100 for(int i = 1; i <= n; ++i) 101 { 102 l = read(), r = read(); 103 if(l > r) swap(l, r); 104 printf("%d ", val[query(l, r)]); 105 } 106 return 0; 107 }
分块入门到此就结束了 (撒花撒花
莫队的版本等我会了再回来补。