BZOJ 3585/3339 mex/Rmq Problem 莫队

Description

  有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。

Input

  第一行n,m。
  第二行为n个数。
  从第三行开始,每行一个询问l,r。

Output

  一行一个数,表示每个询问的答案。

Sample Input

5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5

Sample Output

1
2
3
0
3

HINT

数据规模和约定

  对于100%的数据:

  1<=n,m<=200000

  0<=ai<=109

  1<=l<=r<=n


  对于30%的数据:


  1<=n,m<=1000

Source






双倍经验~~~
莫队或者主席树都可以做……主席树应该会更优一点,下次写一发。

莫队里面维护最小未出现的最小值即可,
当移除一个数,假如这个数出现次数为0那么判断答案min即可;
当加入一个数,假如当前答案ans,然后加入的数恰好为ans的话,
while (ans的出现次数不为1)  ans++。
时间主要在这里吧= =

主席树做法下次写好了……感觉会比莫队快得多。

但是出了点问题……就是莫队add,remove等等4个while的顺序
如果调换有时候就会wa……
按理来说不会wa的。。
求大神解释吧……


#include<bits/stdc++.h>
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int 
	N=200005,
	Block=450;
int n,m,ans;
int a[N],Ans[N],num[N];
struct Query{
	int L,R,id;
}Q[N];
bool cmp(Query x,Query y){
	if ((x.L/Block)==(y.L/Block)) return x.R<y.R;
	return x.L<y.L;
}
void add(int x){
	if (a[x]>n || !x) return;
	num[a[x]]++;
	if (ans==a[x])
		while (num[ans]) ans++;
}
void remove(int x){
	if (a[x]>n || !x) return;
	num[a[x]]--;
	if (!num[a[x]]) ans=min(ans,a[x]);
}
int main(){
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=read(); 
	for (int i=1;i<=m;i++)
		Q[i].L=read(),Q[i].R=read(),
		Q[i].id=i;
	sort(Q+1,Q+1+m,cmp);
	int L=0,R=0;ans=0;
	for (int i=1;i<=m;i++){
		while (R<Q[i].R) add(++R);
		while (L<Q[i].L) remove(L++);
		while (L>Q[i].L) add(--L);
		while (R>Q[i].R) remove(R--);
		Ans[Q[i].id]=ans;
	}
	for (int i=1;i<=m;i++)
		printf("%d\n",Ans[i]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值