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;
}
posted @ 2021-06-28 23:53  acmloser  阅读(32)  评论(0编辑  收藏  举报