UVA 11235 Frequent values (RMQ )
询问静态区间最值的Sparse—Table(Tarjan提出)的算法。这个算法的思想是一个dp,dp[i][j]表示i开头长度为2^j的区间内的最值,然后倍增转移。
这道题询问的是出现次数,相同的数字是连续出现的,先把连续出现的数字按段编号,记录出现的次数。
因为题目询问给的是原来的数字的下标,记录一下这个位置对应的编号。对于完整包含在询问区间里的段,可直接套用RMQ,
为了处理不完整的区间,还需要记录段在原来数组中的左右端点。
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5+5; int id[maxn]; int cnt[maxn],l[maxn],r[maxn]; int d[maxn][20]; void RMQ_init(int *A,int n) { for(int i = 0; i < n; i++) d[i][0] = A[i]; for(int j = 1; (1<<j)<=n; j++){ int t = (1<<j)-1; for(int i = 0; i + t<= n; i++){ d[i][j] = max(d[i][j-1],d[i+(t>>1)][j-1]); } } } int RMQ(int L,int R) { int k = 0; while((1<<(k+1))<=R-L+1) k++; return max(d[L][k],d[R-(1<<k)+1][k]); } int main() { //freopen("in.txt","r",stdin); int n,q; while(scanf("%d%d",&n,&q),n){ int pre; scanf("%d",&pre); int id_cnt = 0; cnt[0] = 1; l[0] = 0; id[0] = 0; for(int i = 1; i < n; i++){ int cur; scanf("%d",&cur); if(cur == pre){ cnt[id_cnt]++; }else { r[id_cnt++] = i-1; l[id_cnt] = i; cnt[id_cnt] = 1; } id[i] = id_cnt; pre = cur; } r[id_cnt++] = n-1; RMQ_init(cnt,id_cnt); while(q--){ int i,j; scanf("%d%d",&i,&j); int ans; if(id[--j] != id[--i]){ ans = max(r[id[i]]-i,j-l[id[j]])+1; if(id[j]-id[i]>1){ ans = max(ans,RMQ(id[i]+1,id[j]-1)); } }else { ans = j-i+1; } printf("%d\n",ans); } } return 0; }