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;
}
浙公网安备 33010602011771号