BZOJ 3339: Rmq Problem


3339: Rmq Problem

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 1237   Solved: 646
[ Submit][ Status][ Discuss]

Description

Input

Output

Sample Input

7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7

Sample Output

3
0
3
2
4

HINT




/*
1 到i(1<=i<=n)的mex可以线性求出来.
考虑l到r和l+1 到r 的答案有何不同.
令next[l] 表.A[L] 下次出现的位置.
显然是l 到next[l]-1 这段所有sg 值大于于a[l] 的变为a[l]
然后线段树维护一下就可以了.
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 200010
#define INF 0x7fffffff
struct Question{ int l,r,order,ans; }query[MAXN];
bool cmp1(Question a,Question b){ return a.l<b.l; }
bool cmp2(Question a,Question b){ return a.order<b.order; }
struct Seg_Tree{int l,r,mn,tag;}tre[MAXN<<3];
int n,q,mex[MAXN],a[MAXN],last[MAXN],next[MAXN],c[MAXN];
void Build(int u,int l,int r){
	tre[u].l=l;tre[u].r=r;tre[u].tag=INF;
	if(l==r){ tre[u].mn=mex[l];return; }
	int Mid=(l+r)>>1;
	Build(u<<1,l,Mid);
	Build(u<<1|1,Mid+1,r);
}
void Modify(int u,int l,int r,int c){
	if(l<=tre[u].l&&tre[u].r<=r){
		tre[u].tag=min(tre[u].tag,c);
		tre[u].mn=min(tre[u].mn,c);
		return ;
	}
	int mid=(tre[u].l+tre[u].r)>>1;
	if(l<=mid) Modify(u<<1,l,r,c);
	if(mid<r) Modify(u<<1|1,l,r,c);
}
int getmn(int u,int pos){
	if(tre[u].l==tre[u].r) return tre[u].mn;
	int mid=(tre[u].l+tre[u].r)>>1,ret=tre[u].tag;
	if(pos<=mid) return min(ret,getmn(u<<1,pos));
	else return min(tre[u].tag,getmn(u<<1|1,pos));
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=q;i++){
		scanf("%d%d",&query[i].l,&query[i].r);
		query[i].order=i;
	}
	sort(query+1,query+1+q,cmp1);
	for(int i=n;i>=1;i--){
		next[i]=last[a[i]];
		if(next[i]==0) next[i]=n+1;
		last[a[i]]=i;
	}
	int now=0;
	for(int i=1;i<=n;i++){
		c[a[i]]=1;
		while(c[now]) now++;
		mex[i]=now;
	}
	Build(1,1,n);
	query[0].l=1;
	for(int i=1;i<=q;i++){
		int prel=query[i-1].l,l=query[i].l;
		for(int j=prel;j<l;j++) Modify(1,j+1,next[j]-1,a[j]);
		query[i].ans=getmn(1,query[i].r);
	}
	sort(query+1,query+1+q,cmp2);
	for(int i=1;i<=q;i++) printf("%d\n",query[i].ans);
	return 0;
}











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值