C.与众不同 (RMQ + 思维)

题目链接

题意:给你一个序列,长度为2e5,序列元素的取值范围【-1e6,1e6】。有q次查询,每次查询l,r,问l到r中完美序列的最大值,完美序列的定义是:一段连续的序列满足序列中的数互不相同。

思路:这个居然可以用RMQ,实在是太神奇了。

首先:我用一个a数组记录i位置往前的第一个非法位置,什么意思呢?

  序列:1 3 2 5 2 2

a数组:0 0 0 0 3 5

对于第一个位置来说,往前没有非法位置,为0,对于最后一个元素来说,往前第一个非法位置是5.

那么:st【i】【0】的定义就是,以i位置为右端点,往前的完美序列的长度,st【i】【1】就是第 i 位置和第 i+1位置中 分别以他们为右端点的完美序列的长度。

那么,我们怎么利用RMQ来求出答案呢。

分情况:如果,a【r】< l,意味着第 r 个位置往前的第一个非法位置不在询问的区间中,所以,答案就是区间长度。否则,在a数组中找到第一个往前非法位置大于等于 l - 1 的位置记为 p ,那么 p 往后的那些位置的非法位置必定大于等于p,往前的那些位置的非法位置必定小于等于p,那么答案就在 p - l 与 区间【p,r】的st值之中


using namespace std;

const int base = 1e6+10,maxn = 2e5+10;
int pre[base*4+100];
int st[maxn][25],a[maxn];

int solve(int l,int r)
{
	int k = log(r-l+1)/log(2);
	int ans = max(st[l][k],st[r-(1<<k)+1][k]);
	return ans;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++)
	{
		int x;
		scanf("%d",&x);
		x += base;
		a[i] = max(a[i-1],pre[x]);
		st[i][0] = i - a[i];
		pre[x] = i;
	}
	
	for(int j = 1; (1<<j) <= 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]);
	
	while(m--)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		++l,++r;
		if(a[r] < l)
		{
			printf("%d\n",r-l+1);
			continue;
		}
		int p = lower_bound(a+1,a+1+n,l-1) - a;
		int ans = max(p-l,solve(p,r));
		printf("%d\n",ans);
	}
 } 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值