uva11235 - Frequent values(RMQ)
看来传闻不差,数据结构的代码真的很长。。。
刘汝佳厚书P198。。。
查询优化,,,
以下摘自刘汝佳训练指南:
把整个数组进行游程编码,用value[],coun[]数组记录第i段的数值和出现次数,用num[p]、left[p]、right[p]记录位置p处所在段的编号和左右端点的位置,,,
所以最后只需对3个部分求最大值即可。
第一部分,左端,right[L]-L+1
第二部分,中间,RMQ(coun, num[L]+1, num[R]+1);
第三部分,右端,R-left[R]+1
另外要注意:如果L,R在同一段,则答案是R-L+1;
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; #define M 100005 #define INF 0x7fffffff int a[M], value[M], coun[M], num[M], left[M], right[M], dp[M][20], len; queue<int*>que; void RMQ_init() { for(int i = 1; i <= len; ++i) dp[i][0] = coun[i]; for(int j = 1; (1<<j) <= len; ++j) for(int i = 1; i + (1<<j) <= len; ++i) dp[i][j] = max(dp[i][j-1], dp[i+(1<<(j-1))][j-1]); } int RMQ(int L, int R) { if(L>R) return 0; int k = 0; while((1<<(k+1))<= R-L+1) ++k; return max(dp[L][k], dp[R-(1<<k)+1][k]); } int main () { int n, q; int *p; while(scanf("%d",&n), n) { scanf("%d",&q); int cnt = 0; value[0] = INF; for(int i = 1; i <= n; ++i) { scanf("%d",&a[i]); if(a[i]!=value[cnt]) { while(!que.empty()) { p = que.front(); que.pop(); *p = i-1; } ++cnt; value[cnt] = a[i]; coun[cnt] = 1; num[i] = cnt; left[i] = i; que.push(right+i); } else { ++coun[cnt]; num[i] = cnt; left[i] = left[i-1]; que.push(right+i); } } while(!que.empty()) { p = que.front(); que.pop(); *p = n; } len = cnt; RMQ_init(); while(q--) { int L, R, ans; scanf("%d %d",&L, &R); if(R<=right[L]&&L>=left[R]) { printf("%d\n", R-L+1); continue; } ans = max(right[L]-L+1, R-left[R]+1); ans = max(ans, RMQ( num[L]+1, num[R]-1)); printf("%d\n",ans); } } return 0; }