【Ybtoj 第16章例3】与众不同【RMQ问题】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解题思路

l a s t x last_x lastx表示最近的x 出现的位置,一开始全部赋为0.

p i p_i pi 表示以i 结尾完美序列 的起点
递推式: p i = m a x ( p i − 1 , l a s t a [ i ] + 1 ) p_i=max(p_{i-1},last_{a[i]+1}) pi=max(pi1,lasta[i]+1

s t i , 0 st_{i,0} sti,0 表示以i结尾最长完美序列 的长度,很显然 f i = i − p i + 1 ; f_i=i-p_i+1; fi=ipi+1;

然后我们友p的递推式可知,p是一个不下降序列,那么对于一个区间 [ l , r ] , 该 区 间 的 p 值 会 出 现 : 左 边 的 一 部 分 p 值 不 在 [l,r],该区间的p值会出现:左边的一部分p值不在 [l,r]pp[l,r] 区 间 内 , 而 右 边 的 一 部 分 的 p 值 在 区间内,而右边的一部分的p值在 p [ l , r ] [l,r] [l,r]区间内,这个分界点可以二分得到,假设该位置为 n o w now now,则区间 [ l , n o w ] [l,now] [l,now]区间的p值在l左边,答案为 n o w − l + 1 , [ n o w + 1 , r ] now-l+1,[now+1,r] nowl+1[now+1,r]区间内答案为f的最大值。


代码

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

const int INF=1000100;
int n,m,s,t,len,ans,a[200010],last[2000010],p[200010],st[200010][50],lg[200010];

int find(int x,int y)
{
	int l=x,r=y,ans=l;
	
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(p[mid]<x) 
		{
			l=mid+1;
			ans=mid;
		}
		else r=mid-1;
	}
	return ans;
}
int work(int x,int y)
{
//	if(x>y)return 0;
	int k=lg[y-x+1];
	return max(st[x][k],st[y-(1<<k)+1][k]);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	p[1]=1,last[a[1]+INF]=1,st[1][0]=1-p[1]+1;
	for(int i=2;i<=n;i++)
	{
		p[i]=max(p[i-1],last[a[i]+INF]+1);
		st[i][0]=i-p[i]+1;
		last[a[i]+INF]=i;
	}
	lg[0]=-1;
	for(int i=1;i<=n;i++)
		lg[i]=lg[i>>1]+1;
	
	for(int j=1;j<=lg[n];j++)
	{
		for(int i=1;i+(1<<j)-1<=n;i++)
		{
			st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
		}
	}
	
	for(int i=1;i<=m;i++)
	{
		ans=0;
		scanf("%d%d",&s,&t);
		s++,t++;
		len=find(s,t);ans=len-s+1;
		if(len<t)ans=max(ans,work(len+1,t));	
		printf("%d\n",ans); 
	}
} 
	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值