bzoj 2724 [Violet 6]蒲公英 - 分块
Description
Input
修正一下
l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1
Output
Sample Input
6 3
1 2 3 2 1 2
1 5
3 6
1 5
1 2 3 2 1 2
1 5
3 6
1 5
Sample Output
1
2
1
2
1
HINT
修正下:
n <= 40000, m <= 50000
Source
题目大意 强制在线区间众数(第一次如此简洁明了的题目大意)。
首先思考主席树和线段树等等数据结构,然后发现区间众数没有可减性,合并时间复杂度有很高,然后我就不会了。
然后瞄了下数据范围,支持分块大暴力诶!
根据分块常用套路,分块的目标是完整的块内快速出答案,然后两边暴力枚举,所以记录如下两个数组
cnt[i][j] 数j在前i块中出现的次数。
ans[i][j] 第i块到第j块的区间众数。
然而ai <= 1e9,cnt直接MLE,所以要先让离散化整个数组,输出答案的时候映射一下(或者你迷之WA掉这道题)就好了。
这两个都可以暴力,第一个没什么说头,第二就枚举后缀(外层循环i,内层直接枚举第i块开始的元素到数组末尾,边数数,然后更新当前众数,到一个块的结尾再更新答案),然而开始我把第二个的暴力的复杂度算错了,就差点不会做了,注意每次内层for的时候要先memset。
查询的时候因为有前缀和,完整的部分的数量可以O(1)算出,再记录一下两边的counter,边枚边更新答案即可。
因为直接memset会TLE,所以要用一点黑科技,因为枚举的点很少,所以用一个vector记录所有更新的点,然后枚举结束后,把vector中的元素指向的位置挨个设成0。
预处理的时间复杂度显然是,单次查询至多枚举的元素是个,中间的查询时的,所以总时间复杂度为
Code
1 /** 2 * bzoj 3 * Problem#2724 4 * Accepted 5 * Time:5960ms 6 * Memory:10304k 7 */ 8 #include <iostream> 9 #include <cstdio> 10 #include <ctime> 11 #include <cmath> 12 #include <cctype> 13 #include <cstring> 14 #include <cstdlib> 15 #include <fstream> 16 #include <sstream> 17 #include <algorithm> 18 #include <map> 19 #include <set> 20 #include <stack> 21 #include <queue> 22 #include <vector> 23 #include <stack> 24 #ifndef WIN32 25 #define Auto "%lld" 26 #else 27 #define Auto "%I64d" 28 #endif 29 using namespace std; 30 typedef bool boolean; 31 const signed int inf = (signed)((1u << 31) - 1); 32 const signed long long llf = (signed long long)((1ull << 63) - 1); 33 const double eps = 1e-6; 34 const int binary_limit = 128; 35 #define smin(a, b) a = min(a, b) 36 #define smax(a, b) a = max(a, b) 37 #define max3(a, b, c) max(a, max(b, c)) 38 #define min3(a, b, c) min(a, min(b, c)) 39 template<typename T> 40 inline boolean readInteger(T& u){ 41 char x; 42 int aFlag = 1; 43 while(!isdigit((x = getchar())) && x != '-' && x != -1); 44 if(x == -1) { 45 ungetc(x, stdin); 46 return false; 47 } 48 if(x == '-'){ 49 x = getchar(); 50 aFlag = -1; 51 } 52 for(u = x - '0'; isdigit((x = getchar())); u = (u * 10) + x - '0'); 53 ungetc(x, stdin); 54 u *= aFlag; 55 return true; 56 } 57 58 template<typename T>class Matrix{ 59 public: 60 T *p; 61 int lines; 62 int rows; 63 Matrix():p(NULL){ } 64 Matrix(int rows, int lines):lines(lines), rows(rows){ 65 p = new T[(lines * rows)]; 66 } 67 T* operator [](int pos){ 68 return (p + pos * lines); 69 } 70 }; 71 #define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows) 72 73 74 int n, m, q; 75 int cs, cc = 0; 76 int* a; 77 int* sa; 78 int* keyer; 79 Matrix<int> cnt; 80 81 inline void init() { 82 readInteger(n); 83 readInteger(q); 84 cs = sqrt(n + 0.5); 85 a = new int[(n + 1)]; 86 for(int i = 0, s = 0; i < n; i++) { 87 readInteger(a[i]); 88 if(s <= i) cc++, s += cs; 89 } 90 } 91 92 inline void descrete() { 93 sa = new int[(n + 1)]; 94 memcpy(sa, a, sizeof(int) * n); 95 sort(sa, sa + n); 96 m = unique(sa, sa + n) - sa - 1; 97 keyer = new int[(m + 1)]; 98 for(int i = 0; i <= m; i++) 99 keyer[i] = sa[i]; 100 for(int i = 0; i < n; i++) 101 a[i] = lower_bound(sa, sa + m + 1, a[i]) - sa; 102 } 103 104 Matrix<int> ans; 105 int* counter; 106 inline void init_chunks() { 107 ans = Matrix<int>(cc + 1, cc + 1); 108 matset(ans, 0, sizeof(int)); 109 int zs = 0; 110 counter = new int[(m + 1)]; 111 for(int i = 0; i < cc; i++) { 112 memset(counter, 0, sizeof(int) * (m + 1)); 113 for(int j = cs * i; j < n; j++) { 114 counter[a[j]]++; 115 if(counter[a[j]] > counter[zs] || (counter[a[j]] == counter[zs] && a[j] < zs)) 116 zs = a[j]; 117 if(j % cs == cs - 1 || j == n - 1) { 118 int endid = j / cs; 119 ans[i][endid] = zs; 120 } 121 } 122 } 123 124 cnt = Matrix<int>(cc, m + 1); 125 matset(cnt, 0, sizeof(int)); 126 memset(counter, 0, sizeof(int) * (m + 1)); 127 for(int i = 0; i < n; i++) 128 cnt[i / cs][a[i]]++; 129 130 for(int i = 1; i < cc; i++) { 131 for(int j = 0; j <= m; j++) 132 cnt[i][j] += cnt[i - 1][j]; 133 } 134 } 135 136 vector<int> modified; 137 inline void solve() { 138 int last = 0, l, r; 139 // int debugc = 0; 140 while(q--) { 141 readInteger(l); 142 readInteger(r); 143 // l--, r--; 144 l = (l + last - 1) % n; 145 r = (r + last - 1) % n; 146 if(l > r) swap(l, r); 147 if(l / cs == r / cs || l / cs + 1 == r / cs) { 148 int zs = 0; 149 for(int i = l; i <= r; i++/*, debugc++*/) { 150 counter[a[i]]++; 151 modified.push_back(a[i]); 152 if(counter[a[i]] > counter[zs] || (counter[a[i]] == counter[zs] && a[i] < zs)) 153 zs = a[i]; 154 } 155 for(int i = 0; i < (signed)modified.size(); i++/*, debugc++*/) 156 counter[modified[i]] = 0; 157 modified.clear(); 158 last = keyer[zs]; 159 printf("%d\n", keyer[zs]); 160 } else { 161 int le = l / cs, rg = r / cs, zs = ans[le + 1][rg - 1]; 162 for(int i = l; i < (le + 1) * cs; i++/*, debugc++*/) { 163 counter[a[i]]++; 164 modified.push_back(a[i]); 165 if(counter[a[i]] + cnt[rg - 1][a[i]] - cnt[le][a[i]] > counter[zs] + cnt[rg - 1][zs] - cnt[le][zs] || 166 (counter[a[i]] + cnt[rg - 1][a[i]] - cnt[le][a[i]] == counter[zs] + cnt[rg - 1][zs] - cnt[le][zs] && a[i] < zs)) zs = a[i]; 167 } 168 for(int i = rg * cs; i <= r; i++/*, debugc++*/) { 169 counter[a[i]]++; 170 modified.push_back(a[i]); 171 if(counter[a[i]] + cnt[rg - 1][a[i]] - cnt[le][a[i]] > counter[zs] + cnt[rg - 1][zs] - cnt[le][zs] || 172 (counter[a[i]] + cnt[rg - 1][a[i]] - cnt[le][a[i]] == counter[zs] + cnt[rg - 1][zs] - cnt[le][zs] && a[i] < zs)) zs = a[i]; 173 } 174 for(int i = 0; i < (signed)modified.size(); i++/*, debugc++*/) 175 counter[modified[i]] = 0; 176 modified.clear(); 177 last = keyer[zs]; 178 printf("%d\n", keyer[zs]); 179 } 180 // fprintf(stderr, "%d, %d\n", q, debugc); 181 } 182 } 183 184 int main() { 185 // freopen("a.in", "r", stdin); 186 // freopen("a.out", "w", stdout); 187 init(); 188 descrete(); 189 init_chunks(); 190 solve(); 191 return 0; 192 }