Frequent values POJ - 3368
原题链接
考察:线段树 or 思维+RMQ
思路一:
用线段树解法比较容易理解.\(cnt\)记录\([l,r]\)区间的最大次数.它可以由子区间的cnt推来,如果左子区间的右端点 = 右子区间的左端点,那么也可以由左子区间的右连续最大长度+右子区间左连续最大长度推来.
需要注意的是查询和push_up一个思路,但是要注意右连续左连续都不能超过查询区间.
思路二:
RMQ的解法,但需要一点转化.用\(nums[i]\)记录以\(a[i]\)结尾的最大连续长度.\(f[i][j]\)表示以\(以[i,i+2^j]区间的a[i]为结尾\)的最大次数.
处理查询就是先找到以左端点为起点的连续次数,右半部分可以通过\(f[i][j]\)求.
Code 线段树
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1000010;
struct Node{
int l,r,cnt,lmax,rmax;
}tr[N<<2];
int a[N],n,m;
int get(int u)
{
return tr[u].r-tr[u].l+1;
}
void push_up(int u)
{
tr[u].lmax = tr[u<<1].lmax;
tr[u].rmax = tr[u<<1|1].rmax;
tr[u].cnt = max(tr[u<<1].cnt,tr[u<<1|1].cnt);
if(a[tr[u<<1].r]==a[tr[u<<1|1].l])
{
if(tr[u<<1].lmax==get(u<<1)) tr[u].lmax+=tr[u<<1|1].lmax;
if(tr[u<<1|1].rmax==get(u<<1|1)) tr[u].rmax+=tr[u<<1].rmax;
tr[u].cnt = max(tr[u<<1|1].lmax+tr[u<<1].rmax,tr[u].cnt);
}
}
void build(int u,int l,int r)
{
tr[u].l = l,tr[u].r = r;
if(l==r) {tr[u].cnt = tr[u].lmax = tr[u].rmax = 1;return;}
int mid = l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
push_up(u);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].cnt;
int mid = tr[u].l+tr[u].r>>1,res = 0;
if(l<=mid) res = max(res,query(u<<1,l,r));
if(mid<r) res = max(res,query(u<<1|1,l,r));
if(tr[u<<1].r>=l&&tr[u<<1|1].l<=r)
{
int x = tr[u<<1].r,y = tr[u<<1|1].l;
if(a[x]!=a[y]) return res;
int rs = min(tr[u<<1].r-l+1,tr[u<<1].rmax);
int ls = min(r-tr[u<<1|1].l+1,tr[u<<1|1].lmax);
res = max(rs+ls,res);
}
return res;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF&&n)
{
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(1,l,r));
}
}
return 0;
}
Code RMQ
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
const int N = 1000010,M = 1000000,S = 22;
int n,m,f[N][S],maxn,a[N],nums[N];
void init()
{
for(int j=0;j<S;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
if(!j) f[i][j] = nums[i];
else f[i][j] = max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF&&n)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(i==1||a[i]!=a[i-1]) nums[i] = 1;
else nums[i] = nums[i-1]+1;
}
init();
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
int idx = upper_bound(a+1,a+n+1,a[l])-a;
if(idx>r) printf("%d\n",r-l+1);
else{
int k = log(r-idx+1)/log(2);
int res = max(f[idx][k],f[r-(1<<k)+1][k]);
res = max(res,idx-l);
printf("%d\n",res);
}
}
}
return 0;
}