范围最值问题,O(nlogn)的预处理,O(1)的查询。
这个题就是先对这些数列进行游程编码,重复的元素只记录下重复的次数。
对于所查询的[L, R]如果它完全覆盖了某些连续的重复片段,那么查询的就是这几种元素重复最多的次数,也就是RMQ。
如果[L, R]还覆盖了某一部分边界,也要单独计算取最大值。
还有个特殊情况就是查询区间都在某一个元素的重复片段中,答案直接就是R-L+1
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 100000 + 10; 7 const int maxl = 20; 8 9 struct RMQ 10 { 11 int d[maxn][maxl]; 12 void Init(const vector<int>& a) 13 { 14 int n = a.size(); 15 for(int i = 0; i < n; i++) d[i][0] = a[i]; 16 for(int j = 1; (1<<j) <= n; j++) 17 for(int i = 0; i + (1<<j) - 1 < n; i++) 18 d[i][j] = max(d[i][j-1], d[i + (1<<(j-1))][j-1]); 19 } 20 21 int query(int L, int R) 22 { 23 int k = 0; 24 while(1<<(k+1) <= R-L+1) k++; 25 return max(d[L][k], d[R-(1<<k)+1][k]); 26 } 27 }; 28 29 int a[maxn], num[maxn], left[maxn], right[maxn]; 30 RMQ rmq; 31 32 int main() 33 { 34 //freopen("in.txt", "r", stdin); 35 36 int n, q; 37 while(scanf("%d%d", &n, &q) == 2) 38 { 39 for(int i = 0; i < n; i++) scanf("%d", &a[i]); 40 a[n] = a[n-1] + 1; 41 vector<int> count; 42 for(int i = 0; i < n; ) 43 { 44 int j = i; 45 while(a[j] == a[i]) j++; 46 count.push_back(j-i); 47 for(int k = i; k < j; k++) 48 { 49 num[k] = count.size() - 1; 50 left[k] = i; 51 right[k] = j - 1; 52 } 53 i = j; 54 } 55 56 //for(int i = 0; i < count.size(); i++) printf("%d\n", count[i]); 57 58 rmq.Init(count); 59 while(q--) 60 { 61 int L, R, ans; 62 scanf("%d%d", &L, &R); L--; R--; 63 if(num[L] == num[R]) ans = R - L + 1; 64 else 65 { 66 ans = max(right[L]-L+1, R-left[R]+1); 67 if(num[L] + 1 < num[R]) 68 { 69 ans = max(ans, rmq.query(num[L]+1, num[R]-1)); 70 } 71 } 72 printf("%d\n", ans); 73 } 74 } 75 76 return 0; 77 }
代码君
时间: 2024-10-06 10:14:42